[英]Is there a way to see the native code produced by theJITter for given C# / CIL?
在對這個答案的評論中(建議使用位移運算符而不是整數乘法/除法,為了提高性能),我詢問這實際上是否會更快。 在我的腦海中有一個想法,在某種程度上 ,某些東西將足夠聰明,以確定>> 1
和/ 2
是相同的操作。 但是,我現在想知道這是否真的是真的,如果是,它會發生在什么級別。
測試程序為兩種方法產生以下比較CIL( optimize
開啟),這兩種方法分別對其參數進行划分和移位:
IL_0000: ldarg.0
IL_0001: ldc.i4.2
IL_0002: div
IL_0003: ret
} // end of method Program::Divider
與
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: shr
IL_0003: ret
} // end of method Program::Shifter
所以C#編譯器發出div
或shr
指令,而不是聰明。 我現在想看看JITter生成的實際x86匯編程序,但我不知道如何執行此操作。 它甚至可能嗎?
編輯添加
感謝您的回答,已接受來自nobugz的那個,因為它包含有關該調試器選項的關鍵信息。 最終對我有用的是:
Tools | Options | Debugger
Tools | Options | Debugger
Tools | Options | Debugger
,關閉'抑制模塊負載的JIT優化'(即我們希望允許 JIT優化) Debugger.Break()
語句 至少可以說結果很有啟發性 - 事實證明JITter實際上可以做算術! 這是來自“反匯編”窗口的已編輯樣本。 各種-Shifter
方法使用>>
除以2的冪; 各種-Divider
方法除以整數使用/
Console.WriteLine(string.Format("
{0}
shift-divided by 2: {1}
divide-divided by 2: {2}",
60, TwoShifter(60), TwoDivider(60)));
00000026 mov dword ptr [edx+4],3Ch
...
0000003b mov dword ptr [edx+4],1Eh
...
00000057 mov dword ptr [esi+4],1Eh
兩種靜態除2方法不僅內聯,而且實際計算由JITter完成
Console.WriteLine(string.Format("
{0}
divide-divided by 3: {1}",
60, ThreeDivider(60)));
00000085 mov dword ptr [esi+4],3Ch
...
000000a0 mov dword ptr [esi+4],14h
與靜態除以3相同。
Console.WriteLine(string.Format("
{0}
shift-divided by 4: {1}
divide-divided by 4 {2}",
60, FourShifter(60), FourDivider(60)));
000000ce mov dword ptr [esi+4],3Ch
...
000000e3 mov dword ptr [edx+4],0Fh
...
000000ff mov dword ptr [esi+4],0Fh
並且靜態除以4。
最好的:
Console.WriteLine(string.Format("
{0}
n-divided by 2: {1}
n-divided by 3: {2}
n-divided by 4: {3}",
60, Divider(60, 2), Divider(60, 3), Divider(60, 4)));
0000013e mov dword ptr [esi+4],3Ch
...
0000015b mov dword ptr [esi+4],1Eh
...
0000017b mov dword ptr [esi+4],14h
...
0000019b mov dword ptr [edi+4],0Fh
它是內聯的,然后計算所有這些靜態分區!
但是如果結果不是靜態的呢? 我添加到代碼中以從控制台讀取整數。 這就是它為此所產生的分歧:
Console.WriteLine(string.Format("
{0}
shift-divided by 2: {1}
divide-divided by 2: {2}",
i, TwoShifter(i), TwoDivider(i)));
00000211 sar eax,1
...
00000230 sar eax,1
因此,盡管CIL不同,但JITter知道除以2是右移1。
Console.WriteLine(string.Format("
{0}
divide-divided by 3: {1}", i, ThreeDivider(i)));
00000283 idiv eax,ecx
它知道你必須除以3除以。
Console.WriteLine(string.Format("
{0}
shift-divided by 4: {1}
divide-divided by 4 {2}",
i, FourShifter(i), FourDivider(i)));
000002c5 sar eax,2
...
000002ec sar eax,2
它知道除以4是右移2。
最后(最好的!)
Console.WriteLine(string.Format("
{0}
n-divided by 2: {1}
n-divided by 3: {2}
n-divided by 4: {3}",
i, Divider(i, 2), Divider(i, 3), Divider(i, 4)));
00000345 sar eax,1
...
00000370 idiv eax,ecx
...
00000395 sar esi,2
它已經內聯了方法,並根據靜態可用的參數找出了最好的方法。 尼斯。
所以,是的,在某處C#和86之間的堆棧,什么是足夠聰明的制定出>> 1
和/ 2
是相同的。 所有這些在我的腦海中給予了更多的重視,我認為將C#編譯器,JITter和CLR加在一起比我們可以嘗試作為簡陋的應用程序程序員的任何小技巧更加巧妙 :)
在配置調試器之前,您將無法獲得有意義的結果。 工具+選項,調試,常規,關閉“抑制模塊加載時的JIT優化”。 切換到發布模式配置。 示例代碼段:
static void Main(string[] args) {
int value = 4;
int result = divideby2(value);
}
如果反匯編看起來像這樣,你就是這樣做的:
00000000 ret
您將不得不欺騙JIT優化器以強制評估表達式。 使用Console.WriteLine(變量)可以提供幫助。 然后你應該看到這樣的事情:
0000000a mov edx,2
0000000f mov eax,dword ptr [ecx]
00000011 call dword ptr [eax+000000BCh]
是的,它在編譯時評估了結果。 工作得很好,不是嗎。
是。 Visual Studio有一個內置的反匯編程序來做到這一點。 您必須將命令添加到菜單欄。 轉到Extras / Customize / Commands(我不知道它們是否真的在英文版本中被稱為),並在菜單欄的某處添加命令Dissassembly,它是unter Debugging。
然后,在程序中設置斷點,當它斷開時,單擊此反匯編命令。 VS將向您顯示反匯編的機器代碼。
Divider方法的示例輸出:
public static int Divider(int intArg)
{
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,34h
00000009 mov esi,ecx
0000000b lea edi,[ebp-38h]
0000000e mov ecx,0Bh
00000013 xor eax,eax
00000015 rep stos dword ptr es:[edi]
00000017 mov ecx,esi
00000019 xor eax,eax
0000001b mov dword ptr [ebp-1Ch],eax
0000001e mov dword ptr [ebp-3Ch],ecx
00000021 cmp dword ptr ds:[00469240h],0
00000028 je 0000002F
0000002a call 6BA09D91
0000002f xor edx,edx
00000031 mov dword ptr [ebp-40h],edx
00000034 nop
return intArg / 2;
00000035 mov eax,dword ptr [ebp-3Ch]
00000038 sar eax,1
0000003a jns 0000003F
0000003c adc eax,0
0000003f mov dword ptr [ebp-40h],eax
00000042 nop
00000043 jmp 00000045
}
在進行調試時(僅在調試時),只需單擊Debug - Windows - Disassembly或按相應的快捷鍵Ctrl + Alt + D.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.