• 0.033秒的艺术 Know System.Math Cost


    0.033秒的艺术 --- the Cost of System.Math

    仅供个人学习使用,请勿转载,勿用于任何商业用途。 

         在对.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个函数与汇编代码的效率一样。

    Code

    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):

    Code

         查看这几个函数的IL代码,可以发现它们都被标记为” cil managed internalcall”。MS所有文档中对这个标记的解释都非常少,实际上它们将调用一些内部的非托管代码。在SOS的帮助下,可以发现Math.Tan的实际地址位于7A2C37FB,相应的代码则是:

    Code

         对于Math.Tan,最终仍然生成了fptan这样的cpu指令,但为什么和sin的差别会那么大呢,确实比较奇怪。至于另外剩下的函数,虽然算法不同,但实现的手段都是类似的,都是用非托管代码所写,并且可能导致多次对其他内部函数的调用。感兴趣可以用sos逐个查看。

    3. Math.Abs. 这个函数比较特别,参数类型不同,所生成的代码也不同。对于浮点数来说,将会直接映射为浮点汇编指令fabs。对于int,却出乎意料的复杂。代码会想检查参数是否为负数,如果是,则需要进一步调用函数System.Math.AbsHelper,这是Math类的一个私有方法,它会进一步检查数据是否会溢出。如果不考虑安全性,自己编写一个简单的整数绝对值表达式要高效很多:

    Code

      4. Math.Max, Math.Min则是用普通托管语言编写的代码,没有特别优化,但这2个方法是inline的。

  • 相关阅读:
    Java 泛型,你了解类型擦除吗?
    终于有人把 Nginx 说清楚了,图文详解!
    给你一份超详细 Spring Boot 知识清单
    Java 中的 SPI 机制是什么鬼?
    用 Git 和 Github 提高效率的 10 个技巧!
    聊聊微服务架构及分布式事务解决方案!
    python多线程同步机制Lock
    python多线程同步机制Semaphore
    mysql 慢查询时间
    mysql row模式查看原始sql
  • 原文地址:https://www.cnblogs.com/clayman/p/1459062.html
Copyright © 2020-2023  润新知