VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Objective-C编程 >
  • the const of System.math

制作者:剑锋冷月 单位:无忧统计网,www.51stat.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的。
  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]
 


相关教程