c# - 为什么代码大小对于 JIT 编译很重要?

标签 c# performance assembly jit

假设您正在使用 JIT 编译的语言进行开发。就生成的程序集的代码大小而言,使函数变得非常大是否会对性能产生负面影响?

我问这个是因为我正在查看 Buffer.MemoryCopy 的源代码前几天在 C# 中,这显然是一种对性能非常敏感的方法。看来他们使用了一个大的 switch 语句来专门针对所有字节数 <= 16 的函数,导致 some pretty gigantic生成的程序集。

这种方法在性能方面有什么缺点吗?例如,我注意到 glibcFreeBSD尽管 C 是 AOT 编译的,但 memmove 的实现不会这样做,这意味着它不会受到 JIT precompilation 成本的影响。 (这是一个缺点)——对于 C#,JIT 会等到第一次调用才编译方法,因此对于很长的方法,第一次调用将花费更长的时间。

对于 JIT 语言来说,拥有巨大的 switch 语句和增加代码大小(除了我刚才提到的预编译成本)有什么优点/缺点?谢谢。 (我对组装有点陌生,所以请对我放轻松:))

最佳答案

假设是 x86。

获取1和解码2指令不是免费的。

与数据缓存类似,CPU也有代码缓存;但通常较小,范围从 8 KiB 到 32 KiB。
较短的代码更适合 I-cache,需要更少的内存读取。

然而,获取只是故事的一半。
x86 在解码方面历来存在问题,因为它的(非常)可变长度指令。 为了实现快速解码,过去和现在都有各种可遵循的模式和解决方法的限制。

自 Core2 架构以来,CPU 在解码器3之后还有其他指令缓存。
这些缓存保存已解码的指令,绕过了前一阶段的限制和延迟。

只是为了有一个想法,我画了 Haswell 解码单元的草图4:

                                              Haswell decoding

每个箭头都是数据路径中的一个步骤,通常需要一个时钟。
深色阴影区域是可以找到说明的地方。

缓存距离乱序核心5越近,意味着位于底部,所述缓存中的指令到达核心的速度就越快。
但是,缓存越近,它就越小,因此减少代码大小可以提高性能,特别是对于关键循环6


我是根据Agner Fog的分析得出这些结论的。 .


1凭内存朗读的行为。
2 将指令转换为微操作的操作。
3 Core2 的预解码器,但仍然如此。
4 Peter,欢迎指出错误:)。
5 CPU中有效执行指令的部分。
6循环意味着经常执行。

关于c# - 为什么代码大小对于 JIT 编译很重要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38471107/

相关文章:

c# - 通过一个排序变量对各种对象的数据结构进行排序的最佳方法?

performance - Fortran 暗示做写加速

c++ - 从 C++ 重定位动态执行的 ARM ASM 系统调用

assembly - x86 NASM 程序集 - 堆栈问题

c - 'switch' 比 'if' 快吗?

c# - 使用 PlayOneShot 时如何停止音频

c# - WPF 将按钮绑定(bind)到命令

c# - 为什么只有 AVX 的处理器在许多 SIMD 算法方面优于 AVX2 处理器?

Android HTML Jsoup解析速度

c# - TimeSpan的比较好慢