Jam*_* Ko 2 c# performance assembly jit
假设您正在使用 JIT 编译语言进行开发。就生成的程序集的代码大小而言,使您的函数变得非常大是否有任何性能下降?
我问是因为我前几天在 C#中查看 Buffer.MemoryCopy的源代码,这显然是一种对性能非常敏感的方法。看来他们使用了一个大switch语句来专门针对所有字节计数<= 16 的函数,从而产生了一些非常庞大的生成程序集。
这种方法在性能方面有什么缺点吗?例如,我注意到glibc和FreeBSD 的实现memmove不这样做,尽管 C 是 AOT 编译的,这意味着它不会受到JIT 预编译的成本(这是一个缺点)——对于 C# ,JIT 会等到第一次调用编译该方法,因此对于非常长的方法,第一次调用将花费更长的时间。
switch对于 JIT 语言来说,拥有庞大的语句和增加代码大小(除了我刚才提到的预编译成本)有什么好处/坏处?谢谢。(我对组装有点陌生,所以请对我放轻松:))
假设 x86。
获取1条指令和解码2条指令不是免费的。
与数据缓存类似,CPU 也有代码缓存;但它通常更小,范围从 8 KiB 到 32 KiB。
较短的代码更适合 I-cache,需要较少的内存提取。
然而,获取只是故事的一半。
由于其(非常)可变长度指令,x86 在解码方面历来存在问题。已经存在并且存在各种需要遵循的模式和解决方法的限制以实现快速解码。
由于 Core2 架构,CPU 具有位于解码器3之后的其他指令缓存。
这些高速缓存保存已解码的指令,绕过前一阶段的限制和延迟。
只是为了有一个想法,我勾勒了 Haswell 解码单元4:
每个箭头都是数据路径中的一个步骤,通常需要一个时钟。
深色阴影区域是可以找到说明的地方。
缓存越接近 Out of Order 核心5,意味着位于底部,所述缓存中的指令到达核心的速度就越快。
然而,缓存越近,它就变得越小,因此减少代码大小可以提高性能,特别是对于关键循环6。
我是根据Agner Fog的分析得出这些结论的。
1从记忆中读取的行为。
2将指令转换为微操作的操作。
3 Core2 的预解码器,但仍然如此。
4 Peter,欢迎您指出错误:)。
5 CPU 中有效执行指令的部分。
6循环意味着经常执行。