Оптимизация JIT в сценарии, сочетающем свойство встроенного и неизменяемого логического модуля - PullRequest
5 голосов
/ 22 января 2011

В следующей программе

module Program

let condition = System.DateTime.Now.Millisecond % 2 = 0

let inline reliesOnCondition (x:int) =
    if condition then
        printfn "%i" x

[<EntryPoint>]
let main args =
    reliesOnConditional System.DateTime.Now.Second
    0

оптимизирует ли JIT выражение reliesOnCondition System.DateTime.Now.Second, если condition окажется ложным при загрузке модуля?

Ответы [ 2 ]

4 голосов
/ 22 января 2011

Нет *.Когда F # выдает IL для программы, все обращения к condition осуществляются через средство доступа к свойству.Из-за этого дополнительного уровня косвенности движок JIT не может оптимизировать все тело reliesOnCondition.

Позвольте мне показать, как я это выяснил.(Также перечислено в старом блоге пост.)

Создание нового проекта F # 'SOQ'

Создайте наше приложение F #.Я просто жестко запрограммировал условие: false.

module Program

let condition = false

let inline reliesOnCondition (x:int) =
    if condition then
        printfn "%i" x

[<EntryPoint>]
let main args =
    printfn "(attach a debugger and press any key)"
    System.Console.ReadKey(true) |> ignore

    reliesOnCondition System.DateTime.Now.Second
    0

Разберите его и соберите его с кодами IL в PDB

Далее используйте ildasm дляразберите бинарный файл IL с помощью параметра /SOURCE.Это не только даст вам IL-дамп исходного кода, но также включает исходный исходный код, оставленный в качестве комментариев.

ildasm SOQ.exe /OUT=SOQ-annotated.exe.il /SOURCE

Соберите наш двоичный файл из IL

Затем используйте ilasm для повторной сборки двоичного файла IL, но передайте флаг /DEBUG, чтобы получить PDB.Полученное приложение будет иметь два уровня кода.Во-первых, исходный F # будет оставлен в виде комментариев, а фактическим кодом будут инструкции IL.

ilasm SOQ-annotated.exe.il /DEBUG

Запустите процесс и подключите отладчик Visual Studio

Запустите недавно аннотированную программу.Это приведет к тому, что приложение получит JIT-тед, как обычно.Затем присоедините отладчик Visual Studio к активному процессу.

Пошаговый код

Просмотр дампа IL в отладчике VS недостаточен.Щелкните правой кнопкой мыши в окне «Stack Traces» и выберите Перейти к разборке .Это даст вам отображение актуальных x86-инструкций.

Вот дамп кода операции x86.Обратите внимание на исходную строку исходного кода F # вверху (ildasm /SOURCE), инструкции IL под ним (ilasm /DEBUG) и инструкции x86 ниже (любезно предоставлены Visual Studio).

//000014:     reliesOnCondition System.DateTime.Now.Second
    IL_0026:  call       valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()
000000db  lea         ecx,[ebp-58h] 
000000de  call        595E8C00 
    IL_002b:  stloc.3
000000e3  lea         edi,[ebp-30h] 
000000e6  lea         esi,[ebp-58h] 
000000e9  movq        xmm0,mmword ptr [esi] 
000000ed  movq        mmword ptr [edi],xmm0 
    IL_002c:  ldloca.s   V_3
000000f1  lea         eax,[ebp-30h] 
000000f4  mov         dword ptr [ebp-74h],eax 
    IL_002e:  call       instance int32 [mscorlib]System.DateTime::get_Second()
000000f7  mov         ecx,dword ptr [ebp-74h] 
000000fa  call        5960A670 
000000ff  mov         dword ptr [ebp-5Ch],eax 
    IL_0033:  stloc.2
00000102  mov         eax,dword ptr [ebp-5Ch] 
00000105  mov         dword ptr [ebp-28h],eax 
    IL_0034:  call       bool Program::get_condition()
00000108  call        dword ptr ds:[004232D8h] 
0000010e  mov         dword ptr [ebp-60h],eax 
    IL_0039:  brfalse.s  IL_003d
00000111  cmp         dword ptr [ebp-60h],0 
00000115  je          0000011A 
... snip ...

Как вы можетеПосмотрите, инструкция IL 34 вызывает Program::get_condition(), поэтому JIT не имеет достаточно информации для правильного устранения вызова функции no-op.(Обратите внимание, что только функции могут быть помечены как встроенные, поэтому вы не можете идти дальше, чем это.)

* На моей машине (x64 Win7).Существует разница между механизмами JIT x86 и x64, а также тем, использовали ли вы NGEN для создания своего исполняемого файла.Ваш пробег может отличаться.

2 голосов
/ 22 января 2011

Недопустимый ответ неверен, косвенное обращение к свойству свойства в общем случае не препятствует оптимизатору JIT пропускать мертвый код. Самые простые становятся встроенными, учитываются значения времени компиляции . Это означает, что оно не будет оптимизировать выражение, поскольку значение условие известно только во время выполнения. Тот факт, что код становится после того, как значение условие уже известно, не меняет этого, оптимизатор должен иметь возможность определять значение статически. Здесь достаточно только литерала, вы получите один с условной компиляцией (#if в C #). Проверьте этот ответ для получения дополнительной информации об оптимизаторе.

...