簡體   English   中英

有沒有辦法查看由JITter為給定的C#/ CIL生成的本機代碼?

[英]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#編譯器發出divshr指令,而不是聰明。 我現在想看看JITter生成的實際x86匯編程序,但我不知道如何執行此操作。 它甚至可能嗎?

編輯添加

發現

感謝您的回答,已接受來自nobugz的那個,因為它包含有關該調試器選項的關鍵信息。 最終對我有用的是:

  • 切換到發布配置
  • Tools | Options | Debugger Tools | Options | Debugger Tools | Options | Debugger ,關閉'抑制模塊負載的JIT優化'(即我們希望允許 JIT優化)
  • 同一個地方,關閉'啟用我的代碼'(即我們要調試所有代碼)
  • 在某處放置一個Debugger.Break()語句
  • 構建程序集
  • 運行.exe,當它中斷時,使用現有的VS實例進行調試
  • 現在,Disassembly窗口顯示了將要執行的實際x86

至少可以說結果很有啟發性 - 事實證明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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM