Zac*_*dom 3 c++ concurrency x86-64 energy spinlock
我正在为我的最新项目制作一个基于光纤的作业系统,该系统将依赖于使用自旋锁来实现正确的功能。我本来打算使用 PAUSE 指令,因为这似乎是普通现代自旋锁等待部分的黄金标准。然而,在对实现我自己的光纤进行一些研究时,我发现最近机器上的暂停周期持续时间已增加到不利的程度。
我从这里发现了这一点,其中引用了英特尔优化手册,“上一代微架构中 PAUSE 指令的延迟约为 10 个周期,而在 Skylake 微架构上它已扩展到多达 140 个周期,”和“由于 PAUSE 延迟显着增加,对 PAUSE 延迟敏感的工作负载将遭受一些性能损失。”
因此,我想找到 PAUSE 指令的替代方案以在我自己的自旋锁中使用。我读过,在过去,暂停一直是首选,因为它以某种方式节省了能源使用,我猜测这是由于另一个经常引用的事实,即使用暂停以某种方式向处理器发出信号,表明它处于自旋锁之中。我还猜测,这是在功率范围的另一端,为所需的周期数进行一些虚拟计算。
鉴于此,是否有一种最佳情况的解决方案能够接近 PAUSE 的表观能源效率,同时具有作为重复“丢弃”计算的灵活性和低周期计数?
我猜测这是由于另一个经常被引用的事实,即使用 PAUSE 以某种方式向处理器发出信号,表明它处于自旋锁之中。
是的,pause让 CPU 在离开只读旋转等待循环时避免内存顺序错误推测,这就是您应该旋转以避免为尝试解锁该位置的线程创建争用的方式。(不要发送垃圾邮件xchg)。也可以看看:
cmpxchg 是否会在失败时写入目标缓存行?如果不是,对于自旋锁来说它比 xchg 更好吗?pause-如果第一个原子 RMW 未能获得锁定,则旋转只读(使用)。您确实希望从 RMW 尝试开始,这样您就不会获得缓存行的共享副本,然后必须等待另一个非核心请求;如果第一次访问是 RMW(如xchg或 )lock cmpxchg,则内核发出的第一个请求将是 RFO。
通过内联汇编锁定内存操作,使用最小的 x86 asm 自旋锁pause(但不会回退到操作系统辅助的睡眠/唤醒,因此如果锁定线程在持有锁时可能会睡眠,则不合适。)
如果您必须等待另一个核心更改内存中的某些内容,那么比核心间延迟更频繁地检查并没有多大帮助,特别是当您最终看到所做的更改时,您会立即停止等待。
pause慢(较新的英特尔)或快(AMD 和旧的英特尔)如果您的代码pause在检查共享值之间使用多个指令,则应该更改代码以减少执行次数。
另请参阅为什么 AMD-CPU 具有如此愚蠢的暂停计时,以及 Brendan 建议检查rdtsc自旋循环以更好地适应pause不同 CPU 上的未知延迟。
基本上尝试让您的工作负载对延迟不pause那么敏感。这也可能意味着尽量避免等待来自其他线程的数据,或者在锁可用之前执行其他有用的工作。
pause在足够新的 CPU 上,具有 WAITPKG 扩展(Tremont 或 Alder Lake / Sapphire Rapids),umonitor/umwait可以在用户空间中等待内存位置更改,例如旋转,但 CPU 在看到缓存一致性流量时会自行唤醒关于改变,或者类似的事情。尽管这可能比pause必须进入睡眠状态要慢。
(您可以要求umwait仅进入 C0.1,而不是 C0.2,指定寄存器的位 0,并将 EDX:EAX 作为 TSC 截止时间。Intel 表示 C0.2 睡眠状态可提高其他超线程的性能,所以大概这意味着切换回单核活动模式,对存储缓冲区、ROB 等进行取消分区,并且必须等待重新分区才能唤醒该核心。但 C0.1 状态不会去做。)
即使在最坏的情况下,pause也只有大约 140 个核心时钟周期。 这仍然比现代 x86-64 上的 Linux 系统调用快得多,尤其是在 Spectre/Meltdown 缓解措施下。(数千到数万个时钟周期,而syscall+则需要几百个sysret时钟周期,更不用说调用schedule()或者运行其他东西了。)
因此,如果您的目标是最大限度地减少唤醒延迟,但代价是浪费 CPU 时间来旋转更长的时间,那么nanosleep这不是一个选择。pause不过,如果作为旋转几次后的后备,这可能对其他用例有好处。
或者用于futex在值更改或来自另一个进程的通知时休眠。(它不能保证内核将使用monitor/mwait进入睡眠状态,直到发生更改,它会让其他任务运行。因此,futex如果任何服务员已经进入睡眠状态,您确实需要让解锁线程进行系统调用futex。但是您可以仍然创建一个轻量级互斥体,如果没有争用并且没有线程进入睡眠状态,则可以避免锁定器和解锁器中的任何系统调用。)
但到那时,futex您可能正在重现 glibc 的pthread_mutex功能。
| 归档时间: |
|
| 查看次数: |
533 次 |
| 最近记录: |