C++ 锁定空闲队列,加载与未加载CPU
我的CPU是Corei7(4个物理核/8个逻辑核)。我正在测试自由锁定队列的实现。测试是什么?我只是创建了很多线程(“pusher”和“popper”),它们推/弹出元素。我注意到当。。。CPU已加载。因此,当CPU没有相对负载时,它工作得比较慢(相对较多)。而且,当它被加载时,它工作得更快C++ 锁定空闲队列,加载与未加载CPU,c++,multithreading,performance,x86,lock-free,C++,Multithreading,Performance,X86,Lock Free,我的CPU是Corei7(4个物理核/8个逻辑核)。我正在测试自由锁定队列的实现。测试是什么?我只是创建了很多线程(“pusher”和“popper”),它们推/弹出元素。我注意到当。。。CPU已加载。因此,当CPU没有相对负载时,它工作得比较慢(相对较多)。而且,当它被加载时,它工作得更快 如何理解它?我认为这是因为“popper”和“pusher”必须竞争“head/”tail”。(我的意思是由于内存管理而增加节点)。如果popper/pusher更少,那么计数器就更低。但是,请注意,它实际
在内核之间跳转缓存线成本很高。一个内核在试图修改同一内存时,推/弹出速度比相互竞争的4个内核快4倍以上,这听起来很合理 因此,问题似乎在于确定所有线程的总挂钟时间或总CPU时间的变化告诉您代码是否正确
换句话说:您正在测试最大争用情况,在这种情况下,您的线程将所有时间都用于推送和弹出,而不做任何其他工作。在使用此队列的实际代码中,线程所做的其他工作将限制对队列的访问速率,可能会限制很多,因此线程会经常互相踩脚ess。(争用可能会对cmpxchg循环造成严重的性能影响,因为每次只有一个CPU会成功,其余的CPU每次都会重试。) 相关:在测试在高争用和低争用情况下使用锁的并行算法时,提出了相同的观点
也许可以尝试使用一些线程进行只读访问的基准测试 当很多访问都是读取时,无锁算法真的很有用。我猜队列通常会弹出,而不仅仅是读取,所以这对于实际使用来说可能没有意义。但我打赌,如果您的一些线程只是读取共享队列而不是更新它,您会看到不同的结果。(例如,将其作为链接列表从头到尾遍历)
在编写代码时,另一个有趣的尝试是:在从基准测试中的某个共享内存加载之前添加
pause
指令(\u mm\u pause()
),以避免内存顺序错误推测。(即,在允许负载全局可见之前,CPU推测性地使用加载的值,然后在负载被假定为全局可见时,当该值被另一个内核更改时,CPU必须回滚).请记住,pause
在Haswell上休眠约5个周期,但在Skylake上休眠约100个周期,因此,即使您在Haswell上的非合成基准测试中看到它的加速,将其保留下来供将来的CPU实际使用可能是个坏主意
请注意,pause
在lock
ed read-modify-write指令之前是没有用的;它们已经在等待来自其他内核的写入
通常情况下,你先轻松加载一个cmpxchg,然后再加载一个cmpxchg,所以我建议在加载之前暂停一下。在内核之间跳转缓存线是很昂贵的。一个内核在尝试修改同一内存时,推/弹出的速度比相互竞争的4个内核快4倍以上,这听起来很合理 因此,问题似乎在于确定所有线程的总挂钟时间或总CPU时间的变化告诉您代码是否正确
换句话说:您正在测试最大争用情况,在这种情况下,您的线程将所有时间都用于推送和弹出,而不做任何其他工作。在使用此队列的实际代码中,线程所做的其他工作将限制对队列的访问速率,可能会限制很多,因此线程会经常互相踩脚ess。(争用可能会对cmpxchg循环造成严重的性能影响,因为每次只有一个CPU会成功,其余的CPU每次都会重试。) 相关:在测试在高争用和低争用情况下使用锁的并行算法时,提出了相同的观点
也许可以尝试使用一些线程进行只读访问的基准测试 当很多访问都是读取时,无锁算法真的很有用。我猜队列通常会弹出,而不仅仅是读取,所以这对于实际使用来说可能没有意义。但我打赌,如果您的一些线程只是读取共享队列而不是更新它,您会看到不同的结果。(例如,将其作为链接列表从头到尾遍历)
在编写代码时,另一个有趣的尝试是:在从基准测试中的某个共享内存加载之前添加
pause
指令(\u mm\u pause()
),以避免内存顺序错误推测。(即,在允许负载全局可见之前,CPU推测性地使用加载的值,然后在负载被假定为全局可见时,当该值被另一个内核更改时,CPU必须回滚).请记住,pause
在Haswell上休眠约5个周期,但在Skylake上休眠约100个周期,因此,即使您在Haswell上的非合成基准测试中看到它的加速,将其保留下来供将来的CPU实际使用可能是个坏主意
请注意,pause
在lock
ed read-modify-write指令之前是没有用的;它们已经在等待来自其他内核的写入
通常情况下,你会先进行一个宽松的加载,然后是一个cmpxchg,所以我建议在加载之前暂停一下。你是说如果你在一个空的CPU上运行测试,它会比你运行ex时运行得慢吗