不同大小的原子操作的性能比较

时间:2015-03-28 20:26:29

标签: performance c++11 atomic

在处理器的自然字大小(4字节或8字节)上运行的原子操作的性能与在其他大小(2字节或1字节)上操作的性能相比如何?

如果我需要维护一个布尔原子变量,我试图弄清楚最佳实践是什么:使用1字节优化空间,或4/8字节(可能)优化性能

1 个答案:

答案 0 :(得分:2)

http://agner.org/optimize/了解了很多细节。

在x86上,1字节数据的数组应该是好的。它可以加载movzx(零扩展),与普通mov一样快。

如果你想用另一个因子8来打包你的数据,那么x86有一些位ops来支持原子位域。不过,我不确定编译器在为这种情况制作高效代码时会做得多好。即使是只写操作,也需要缓慢的原子RMW周期来保存要写入的位的字节。 (在x86上,它是一个lock OR指令,这是一个完整的内存屏障。在Intel Haswell上是8 uops,而在一个字节存储中是1 uops。吞吐量是19。)这可能仍然值得如果它意味着许多缓存未命中和很少缓存未命中之间的差异,尤其是如果大多数访问是只读的。 (读取有点快,与非原子情况完全相同。)

x86上的2字节(16位)操作可能很慢,尤其是在英特尔CPU上。英特尔指令解码器在必须使用16位立即数操作数解码指令时会减速很多。这是操作数大小前缀的dreaded LCP stall。 (8b操作具有完全不同的操作码,并且REX前缀选择32对64位,这不会减慢解码器的速度)。所以16b是奇怪的一个,你应该小心使用它。更喜欢将16b内存加载到32b变量中以避免部分寄存器处罚,并且在处理临时寄存时需要16位内存。 (AMD CPU在处理movzx负载方面效率不高(需要一个ALU单元和额外的1个周期延迟),但内存节省几乎总是值得的(出于缓存原因))。

32b是用于本地临时变量的“最佳”大小。选择该大小(增加代码密度)不需要前缀,并且在使用低8b后再次使用完整寄存器时不会出现部分寄存器停顿或额外微操作。我相信这是int_fast32_t类型的目的,但在x86 Linux上,该类型很不幸是64位。