Почему двухмерная векторная структура добавляется медленнее, чем трехмерная векторная структура в C #? - PullRequest
0 голосов
/ 28 января 2019

Недавно я сделал приложение для тестирования, чтобы изучить несколько подходов к написанию операторов сложения для математических структур в C #: https://github.com/nickgravelyn/math-struct-benchmark. Среди результатов, которые я обнаружил, Vector2 был последовательно медленнее, чем Vector3, несмотря на то, что он имел меньше данных и имелменьше инструкцийБолее интригующим является то, что это, похоже, имеет место в каждой среде выполнения / JIT, которую я тестировал.

Например, при работе на .NET Core 2.2 тест для оператора + для одной из протестированных реализаций Vector2 занял 921,82 мс, тогда как сопоставимая реализация Vector3 заняла 422,76Миз.

Есть ли какая-либо причина из C #, IL или нативной сборки, которая могла бы объяснить, почему я могу видеть эти результаты?Или я что-то испортил в своем тесте где-то, что я не могу заметить?

Ответы [ 2 ]

0 голосов
/ 31 января 2019

После дальнейшего копания проблема с 64-битным кодом RyuJIT gen.У меня есть проблема , поданная в CoreCLR, и кажется, что это связано или идентично другим проблемам с производительностью.

0 голосов
/ 29 января 2019

Я пытаюсь добавить некоторые выводы, хотя пока не отвечаю.BenchmarkDotNet показывал мне те же результаты, что и вы.

Сначала я провел некоторые профилирования в VS с инструментами, чтобы показать, что нет никаких сомнений в том, что само сложение потребляет время и приносит большую разницу.

*Выполнено 1004 * результатов выполнения 64-битного кода: screenshot from VS profiler report

против.32 бита:

enter image description here

код IL этих двух строк:

        // value += value2;
    IL_0059: ldloc.0
    IL_005a: ldloc.1
    IL_005b: call valuetype UserQuery/Vector2_A UserQuery/Vector2_A::op_Addition(valuetype UserQuery/Vector2_A, valuetype UserQuery/Vector2_A)
    IL_0060: stloc.0
    // value3 += value4;
    IL_0061: ldloc.2
    IL_0062: ldloc.3
    IL_0063: call valuetype UserQuery/Vector3_A UserQuery/Vector3_A::op_Addition(valuetype UserQuery/Vector3_A, valuetype UserQuery/Vector3_A)
    IL_0068: stloc.2

, за которыми следуют 2 метода операции добавления, 2 dim:

.method public hidebysig specialname static 
valuetype UserQuery/Vector2_A op_Addition (
    valuetype UserQuery/Vector2_A value1,
    valuetype UserQuery/Vector2_A value2
) cil managed 
{
// Method begins at RVA 0x2100
// Code size 37 (0x25)
.maxstack 3
.locals init (
    [0] valuetype UserQuery/Vector2_A
)

// (no C# code)
IL_0000: nop
// return new Vector2_A(value1.X + value2.X, value1.Y + value2.Y);
IL_0001: ldarg.0
IL_0002: ldfld float32 UserQuery/Vector2_A::X
IL_0007: ldarg.1
IL_0008: ldfld float32 UserQuery/Vector2_A::X
IL_000d: add
IL_000e: ldarg.0
IL_000f: ldfld float32 UserQuery/Vector2_A::Y
IL_0014: ldarg.1
IL_0015: ldfld float32 UserQuery/Vector2_A::Y
IL_001a: add
IL_001b: newobj instance void UserQuery/Vector2_A::.ctor(float32, float32)
IL_0020: stloc.0
// (no C# code)
IL_0021: br.s IL_0023

IL_0023: ldloc.0
IL_0024: ret
} // end of method Vector2_A::op_Addition

и 3-мерное:

.method public hidebysig specialname static 
valuetype UserQuery/Vector3_A op_Addition (
    valuetype UserQuery/Vector3_A value1,
    valuetype UserQuery/Vector3_A value2
) cil managed 
{
// Method begins at RVA 0x214c
// Code size 50 (0x32)
.maxstack 4
.locals init (
    [0] valuetype UserQuery/Vector3_A
)

// (no C# code)
IL_0000: nop
// return new Vector3_A(value1.X + value2.X, value1.Y + value2.Y, value1.Z + value2.Z);
IL_0001: ldarg.0
IL_0002: ldfld float32 UserQuery/Vector3_A::X
IL_0007: ldarg.1
IL_0008: ldfld float32 UserQuery/Vector3_A::X
IL_000d: add
IL_000e: ldarg.0
IL_000f: ldfld float32 UserQuery/Vector3_A::Y
IL_0014: ldarg.1
IL_0015: ldfld float32 UserQuery/Vector3_A::Y
IL_001a: add
IL_001b: ldarg.0
IL_001c: ldfld float32 UserQuery/Vector3_A::Z
IL_0021: ldarg.1
IL_0022: ldfld float32 UserQuery/Vector3_A::Z
IL_0027: add
IL_0028: newobj instance void UserQuery/Vector3_A::.ctor(float32, float32, float32)
IL_002d: stloc.0
// (no C# code)
IL_002e: br.s IL_0030

IL_0030: ldloc.0
IL_0031: ret
} // end of method Vector3_A::op_Addition

, если честно, остальное просто догадка, что метод 3 dim add имеет некоторые преимущества с mem / stackвыравнивание, как говорится, размер кода 0x32 против 0x25 и maxstack 4 против 3.

Проверка результатов ассемблера x64 в RjuJIT позволила бы мне исчерпать талант.Может быть стоит за это пинговать JIT экспертов MS?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...