班级成员的顺序会影响访问速度吗?

Jac*_*ath 3 c++ performance micro-optimization class-members addressing-mode

我正在编写一个应该绝对没有开销的委托库。因此,尽可能快地访问函数指针很重要。

所以我的问题是:访问速度是否取决于班级中的成员位置?我听说最重要的成员应该是成员声明中的第一个成员,这对我来说很有意义,因为这意味着this类的指针指向与重要成员相同的地址(假设是非虚拟类)。而如果重要成员将在任何其他位置,CPU 将不得不通过添加this和类布局中的偏移量来计算它的位置。

另一方面,我知道编译器将该地址表示为 a qword-ptr,其中包含偏移量的信息。

所以我的问题归结为:解决 a 是否qword-ptr需要一个恒定的时间,或者如果偏移量不是,它会增加0吗?行为在不同平台上是否保持相同?

Pet*_*des 6

大多数机器都有一个加载指令或寻址模式,可以包括一个小的恒定位移,无需额外成本。

在 x86 上,[reg]对于[reg + disp8]寻址模式的 8 位位移部分,vs.花费 1 个额外字节。在类似 RISC 的机器上,例如 ARM,固定宽度指令意味着加载/存储指令总是有一些位用于位移(可以简单地全为零以访问给定指向对象开头的指针的第一个成员)。


将最热门的成员放在班级的前面,最好按大小排序以避免填充间隙(如何在结构中组织成员以在对齐时浪费最少的空间?希望热门成员都在同一个缓存中线。(如果您的类/结构扩展到第二个缓存行,希望大部分时间只有第一行必须在缓存中保持热状态,从而减少工作集的占用空间。)

如果该成员与对象的开头不在同一页面中,则 Sandybridge 系列的指针追踪优化如果this也从内存中加载,则会导致额外的延迟。 当 base+offset 与 base 位于不同的页面时,是否有惩罚?通常,它将 L1d 负载使用延迟从 5 个周期减少到 4 个周期,例如[rdi + 0..2047]通过乐观地仅使用寄存器值作为 TLB 的输入,但如果猜测错误,则必须重试。(不是管道刷新,只是在没有快捷方式的情况下重试加载 uop。)


请注意,函数指针主要取决于分支预测是否有效,访问延迟仅对检查预测很重要(如果错误,则启动分支恢复)。即推测执行 + 分支预测隐藏了 CPU 中无序执行的延迟控制依赖关系。