2013-02-13 3 views
1

Я перемещаю приложение x86 на x64 и обнаружил, что никакие функции не встроены компилятором. Даже маленький (< 32 байта IL и даже пустой). Даже с опцией компилятора MethodImplOptions.AggressiveInlining.Встроенные функции (.NET x64)

В то время как в x86 все мелкие функции (а также простые большие с возможностью компилятора) встроены без проблем.

Есть ли способ в x64 рассказать компилятору о встроенном им?

Например, следующий код с "Target Platform" = x86 только петли, а с 64 - также вызывает EmptyFunction() 100 миллионов раз:

void LoopFunction() 
{ 
    Stopwatch watch = new Stopwatch(); 
    watch.Start(); 
    for (int i = 0; i < 100000000; i++) 
    { EmptyFunction(); } 
    watch.Stop(); 
    MessageBox.Show(watch.Elapsed.ToString()); 
} 
[MethodImpl(MethodImplOptions.AggressiveInlining)] 
void EmptyFunction() { } 
+0

Как вы тестируете это? Обратите внимание, что некоторые оптимизации отключены во время работы в среде IDE. –

+0

Я протестировал это: из VisualStudio с различными вариантами release/отладки, а также запустив результат .EXE. В VisualStudio это только медленнее, но результат тот же - с x64, который более 10 раз медленнее, чем с x86. –

+2

В вашем случае должно быть что-то еще. Ваш пример для меня. Что я сделал: вставлял ваш код в консольное приложение .NET 4.5, исправлял список использования, менял методы на статические, добавлял Console.ReadLine(), запускал выпуск exe, прикреплял отладчик, устанавливал точку останова после ReadLine, нажал в консоли, перешел в функцию VS. Для меня нет вызовов в цикле for. –

ответ

2

То, что для() петли компилируется в 64-битном режим в .NET 3.5 джиттера

0000002e xor   r11d,r11d 
00000031 add   r11d,4 
      for (int i = 0; i < 100000000; i++) { EmptyFunction(); } 
00000035 cmp   r11d,5F5E100h 
0000003c jl   0000000000000031 

к .NET 4.5 джиттера:

0000003a xor   eax,eax 
0000003c nop   dword ptr [rax] 
00000040 add   eax,4 
      for (int i = 0; i < 100000000; i++) { EmptyFunction(); } 
00000043 cmp   eax,5F5E100h 
00000048 jl   0000000000000040 

Нет вызова, просто цикл выжил, как и следовало ожидать. Команда Weirdo NOP предназначена для выравнивания цели ветви.

Обязательно используйте сборку Release и будьте осторожны с помощью отладчика, поскольку он отключит оптимизатор. Исправьте это с помощью Tools + Options, Debugging, General, отключите опцию «Подавить оптимизацию JIT при загрузке модуля».

+0

Ханс Пассант, я думаю, ты меня не понял (или я тебя не понял). Я писал о функции inlining - когда компилятор заменяет вызов функции своим кодом. В моем примере компилятор должен просто удалить вызов EmptyFunction() из цикла for(), потому что он пуст. Итак, с примером (в режиме Release, конечно): 1) с целевой платформой x86 (или со статической функцией и x64): компилятор удаляет вызов EmptyFunction() и функцию LoopFunction() время выполнения составляет 0,02 секунды - время просто для пустого цикла [0..100000000]. –

+0

2) с нестатической функцией & x64: ее время выполнения равно 0.26 секунд - для каждой функции цикла вызывается функция EmptyFunction(), поэтому ее вызов не был удален компилятором, в то время как это нужно сделать с помощью опции «Агрессивная разметка». Debug/Release, «Suppress JIT ...» и все остальное, что я мог придумать, не помогло - с нестационарными функциями x64 не были включены. –

+0

Хмэ, с учетом отсутствия кода, как известно, сложно. Вы действительно синхронизируете цикл for() и очень маленькие изменения, такие как дополнительный NOP, имеют большие эффекты. Используйте только жесткие доказательства, фактический код является доказательством. –

1

В моем компьютере (.Net 4.5 x64)

Если я использую AggressiveInlining, x86 (все целевые ЦП 32 бит предпочтительно) занимает 36 мс, 64 (мишень все CPU снимите отметку 32 бит предпочтительный) занимает 8 мс.

Если я использую NoInlining, x86 занимает 240 мс, x64 занимает 270 мс.

Итак, это определенно в строках

Смежные вопросы