【问题标题】:Cross-platform implementation of the x86 pause instructionx86暂停指令的跨平台实现
【发布时间】:2013-11-04 23:55:33
【问题描述】:

编写 x86 暂停指令的跨平台实现的最佳实践是什么? 我计划在 C++ 11 项目的繁忙循环中使用它。

如果我只使用 gcc 工具链,那么我可以使用 _mm_pause 内在函数。即使本机处理器不支持 x86 暂停指令,这个内在函数是否正确?我也希望我的代码也能在 clang/llvm 工具链上工作。

我想回退可以使用“std::this_thread::sleep_for”,因为我使用的是 C++ 11。但我不确定如何检测处理器能力(支持暂停与不支持)并返回睡眠。

我正在使用 cmake 来构建我的项目,并且将始终在同一台机器上构建和部署。所以我很乐意在编译期间检测处理器设置。

一个示例实现(伪代码)是:

void pause() {
// Not sure how to detect if pause is available on the platform.
#if defined(USE_mm_pause)
  __asm__ ( "pause;" );
#else
  std::this_thread::sleep_for(std::chrono::seconds(0));
#endif
}

【问题讨论】:

  • 检测指令可用性的方法是编写一个使用它的小程序,然后在编译过程中编译、链接和运行该程序。要么它是工具链和硬件可接受的 ISA 部分,要么你得到一个失败的编译器或一个非法指令的 SIGILL
  • 我更喜欢__asm__ __volatile__("pause;");,这样 GCC 就不会在暂停期间重新排序内存访问。
  • sleep_for 是否与 yield 有任何关系,或者这是巧合,至于 sleep/yield 调度程序会处理您的时间片,而 nop 只是一个 nop。
  • @RedXIII 这是个问题吗? std::this_thread::sleep_for 将运行 sleep 命令,该命令只会使当前线程进入睡眠状态,但不会安排另一个线程在核心上运行。对于 yield,C++ 11 有 std::this_thread::yield 命令。这使调度程序有机会重新调度。
  • 使用_mm_pause() 来自<immintrin.h>。它可移植到包括 MSVC 在内的所有主要编译器。见How do you use the pause assembly instruction in 64-bit C++ code?。 (试图将其作为副本关闭。)

标签: c++ c++11 x86


【解决方案1】:

即使在本机处理器的情况下,此内在函数是否正确? 不支持x86暂停指令?

是的,暂停指令编码为 F3 90。不知道该指令的 Pentium 4 前处理器会将其解码为:

  REP NOP

这只是一个普通的NOP,带有一个无用的前缀字节。处理器将等待一个或两个周期,然后继续,而不以任何方式改变处理器状态。您不会从使用 PAUSE 中获得性能和功耗优势,但该程序仍将按预期运行。

有趣的事实:REP NOP 在大约 35 年前发布的 8086 上甚至是合法的。这就是我所说的向后兼容性。

【讨论】:

  • 感谢您的回答。这似乎是 gcc 的一个很好的解决方案。对其他编译器的支持有何评论,尤其是 clang?
  • 我之前使用的是“xmmintrin.h”标头。我现在已经切换到“x86intrin.h”。似乎它正在使用 gcc 4.3 和 clang 3.3.1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 2018-06-24
  • 1970-01-01
  • 2013-06-23
  • 2018-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多