我最近在32核Skylake Intel处理器上对
是什么让intel多核处理器上的
std::atomic::fetch_add
和std::atomic::compare_exchange_strong
进行了基准测试。并不出乎意料(根据我听到的有关fetch_add的传说),fetch_add几乎比compare_exchange_strong可伸缩性高一个数量级。从程序的反汇编代码来看,std::atomic::fetch_add
使用lock add
实现,而std::atomic::compare_exchange_strong
使用lock cmpxchg
实现(https://godbolt.org/z/qfo4an)。是什么让intel多核处理器上的
lock add
如此快?据我所知,两种指令的速度都受到缓存行争用的影响,并且为了以顺序一致的方式执行两种指令,执行CPU必须将该行以独占或修改模式拉入自己的核心中(来自MESI)。那么处理器如何内部优化fetch_add呢?
这是基准测试代码的简化版本。对于compare_exchange_strong基准测试来说,没有load+CAS循环,只有一个在原子变量上进行compare_exchange_strong的输入变量,该变量会不断地被线程和迭代所改变。因此,这只是在多个CPU竞争下比较指令吞吐量的比较。
fetch_add()
进行基准测试。因为你没有使用被获取的值,编译器将其优化为原子的“不获取,只添加”,而你所测试的是这个“不获取,只添加”的性能。 - Brendanlock xadd
大概只是多了几个 uops,本质上并没有什么不同。但是说得好,这也是 OP 可以测试的另一件事情。 - Peter Cordes