程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> .net中如何得到實際運行時的asm代碼

.net中如何得到實際運行時的asm代碼

編輯:關於.NET

在對.net程序進行調試或者性能測試時,常常需要查看生成的IL代碼,但僅僅有IL代碼還是不夠的,有時我們還希望查看CLR生成的最終asm代碼。在VS裡,可以非常方便的查看最終的asm代碼:當程序執行到斷點時,在代碼窗口右鍵選擇Go To Disassemble就可以。但是,當通過VS Debug程序時,為了方便調試,CLR通常不會生成最優化的代碼。所以為了得到實際運行時的asm代碼,還必須做以下設置:

1,在Release模式下編譯代碼;

2. 打開工程屬性窗口,選擇”Build”頁面--- “Advanced”,彈出窗口的“Debug Info”項設置為”pdb-only”。

3. 打開Tools => Options => Debugging => General,保證Suppress JIT optimization on module load和Enable Just My Code處於未選中狀態。

可以在這裡找到關於配置的更多資料。

我對.net 數學庫做了一系列測試,結果可謂喜憂參半。當然,不同機器上可能得到不同的asm代碼,以下是我的測試配置:intel Q6600 + .net framework 3.5 sp1。下面就來看看System.Math下個函數的性能。測試代碼如下:

array[i] = Math.XXX(array[i]);

1. Math.Sqrt, Math.Sin, Math.Cos是所能期望的最理想實現,三個函數分別直接映射為fsqrt, fsin和fcos三條浮點匯編指令,可以認為這3個函數與匯編代碼的效率一樣。

array[i] = Math.Sqrt(array[i]);
00000092  fild        dword ptr [eax+edx*4+8]
00000096  fsqrt
00000098  fstp        qword ptr [ebx+edx*8+8]

array[i] = Math.Sin(array[i]);
00000092  fild        dword ptr [eax+edx*4+8]
00000096  fsin            
00000098  fstp        qword ptr [ebx+edx*8+8]

2. Math.Asin, Math.Acos, Math.Tan, Math.Atan, Math.floor, Math.Cell, Math.Log,Math.Exp,Math.Floor,Math.Pow,Math.Round以及其他所有以h結尾的三角函數:在Disassemble下,只能看到這些函數並沒有inline。下面是Math.Tan函數的disassemble代碼,在VS裡是無法訪問7935A4AB處的代碼(實際上這個地址也根本不正確,這是vs裡一個邪惡的bug):

            double tan = Math.Tan(c3.X);
00000219  fld         dword ptr [ebp-30h]
0000021c  sub         esp,8
0000021f  fstp        qword ptr [esp]
00000222  call        7935A4AB
00000227  fstp        qword ptr [ebp-38h]

查看這幾個函數的IL代碼,可以發現它們都被標記為” cil managed internalcall”。MS所有文檔中對這個標記的解釋都非常少,實際上它們將調用一些內部的非托管代碼。在SOS的幫助下,可以發現Math.Tan的實際地址位於7A2C37FB,相應的代碼則是:

Unmanaged code
7A2C37FB 55               push        ebp
7A2C37FC 8BEC             mov         ebp,esp
7A2C37FE DD4508           fld         qword ptr [ebp+8]
7A2C3801 D9F2             fptan
7A2C3803 DDD8             fstp        st(0)
7A2C3805 5D               pop         ebp
7A2C3806 C20800           ret         8
7A2C3809 55               push        ebp
7A2C380A 8BEC             mov         ebp,esp
7A2C380C DD4508           fld         qword ptr [ebp+8]

對於Math.Tan,最終仍然生成了fpan這樣的cpu指令,但為什麼和sin的差別會那麼大呢,確實比較奇怪。至於另外剩下的函數,雖然算法不同,但實現的手段都是類似的,都是用非托管代碼所寫,並且可能導致多次對其他內部函數的調用。感興趣可以用sos逐個查看。

3. Math.Abs. 這個函數比較特別,參數類型不同,所生成的代碼也不同。對於浮點數來說,將會直接映射為浮點匯編指令fabs。對於int,卻出乎意料的復雜。代碼會想檢查參數是否為負數,如果是,則需要進一步調用函數System.Math.AbsHelper,這是Math類的一個私有方法,它會進一步檢查數據是否會溢出。如果不考慮安全性,自己編寫一個簡單的整數絕對值表達式要高效很多:

//asm code for Math.Abs(float/double)
00000086  fld         qword ptr [ebx+edx*8+8]
0000008a  fabs
0000008c  fstp        qword ptr [ebx+edx*8+8]

//asm code for Math.Abs(integer)
0000008e  mov         ecx,dword ptr [eax+esi*4+8]
00000092  test        ecx,ecx
00000094  jl          0000009A
00000096  mov         eax,ecx
00000098  jmp         0000009F
0000009a  call        75F1E728  //call Math.AbsHelper if integer is a negative number
0000009f  mov         dword ptr [ebp-24h],eax
000000a2  fild        dword ptr [ebp-24h]
000000a5  cmp         esi,dword ptr [ebx+4]
000000a8  jae         00000286
000000ae  fstp        qword ptr [ebx+esi*8+8]

//asm code for Math.AbsHelper
00000000  push        ebp
00000001  mov         ebp,esp
00000003  push        eax
00000004  cmp         ecx,80000000h
0000000a  je          00725A00
00000010  neg         ecx
00000012  mov         eax,ecx
00000014  mov         esp,ebp
00000016  pop         ebp
00000017  ret         //return if no overflow occurred
00000018  mov         ecx,7994E990h
0000001d  call        FF83A548
00000022  mov         dword ptr [ebp-4],eax
00000025  mov         edx,790C1000h
0000002a  mov         ecx,70005A82h
0000002f  call        FF83A598
00000034  mov         ecx,eax
00000036  call        FF8641C8
0000003b  mov         edx,eax
0000003d  mov         ecx,dword ptr [ebp-4]
00000040  call        FFDCD44C
00000045  mov         ecx,dword ptr [ebp-4]
00000048  call        FF83A5B0
0000004d  int         3

//optimized unsafe abs:
 static public int FastAbs(int a)
{
    return (a >= 0) ? a : -a;
}

//asm code for unsafe abs which is inlined
00000091  mov         eax,dword ptr [ebx+ecx*4+8]
00000095  test        eax,eax
00000097  jge         0000009D
00000099  neg         eax
0000009b  jmp         0000009D
0000009d  cmp         ecx,edx
0000009f  jae         00000296
000000a5  mov         dword ptr [ebx+ecx*4+8],eax

4. Math.Max, Math.Min則是用普通托管語言編寫的代碼,沒有特別優化,但這2個方法是inline的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved