如何在64位C ++代码中使用暂停汇编指令?

时间:2011-04-29 14:42:23

标签: visual-c++ visual-c++-2010

由于VC ++ 2010在64位代码中不支持内联汇编,如何在代码中获得pause x86-64指令?似乎没有像这样的固有的许多其他常见的汇编指令(例如,__rdtsc()__cpuid()等......)。

就原因而言,我希望该指令能够帮助处理繁忙的等待用例,以便(超线程)CPU可用于在所述CPU上运行的其他线程(请参阅:intel.com上的Performance Insights) 。 pause指令对这个用例以及自旋锁实现非常有用,我无法理解为什么MS没有将它作为内在函数包含在内。

由于

2 个答案:

答案 0 :(得分:14)

哇,这是一个非常难以追查的问题,但是如果其他人需要x86-64 pause指令:

YieldProcessor()中的windows.h宏扩展为未记录的_mm_pause内在函数,最终扩展为32位和64位代码中的pause指令。

顺便说一句,对于YieldProcessor()出现在MSDN中的部分(以及VC ++ 2010文档不正确),这完全没有记录。

以下是YieldProcessor()宏编译成块的示例:

    19:     ::YieldProcessor();
000000013FDB18A0 F3 90                pause  
    20:     ::YieldProcessor();
000000013FDB18A2 F3 90                pause  
    21:     ::YieldProcessor();
000000013FDB18A4 F3 90                pause  
    22:     ::YieldProcessor();
000000013FDB18A6 F3 90                pause  
    23:     ::YieldProcessor();
000000013FDB18A8 F3 90                pause  

顺便说一句,每个暂停指令似乎在Nehalem架构上平均产生大约9个周期的延迟(即3.3 GHz CPU上的3 ns)。

答案 1 :(得分:1)

_mm_pause() intrinsic is fully documented by Intel受所有主要的x86编译器支持,可跨操作系统移植。如果过去缺少MS的文档,或者如果您只是错过了大约7年,则可以使用IDK。

#include <immintrin.h>并使用它。 (或对于SSE2的古代编译器#include <emmintrin.h>)。

#include <immintrin.h>

void test() {
    _mm_pause();
    _mm_pause();
}

在gcc / clang / ICC / MSVC(on the Godbolt compiler explorer)的全部4个上编译为该asm:

test():                               # @test()
    pause
    pause
    ret

在没有SSE2的CPU上,它解码为rep nop,而只是nopCross-platform implementation of the x86 pause instruction

Gcc甚至知道这一点,并且在使用_mm_pause()进行编译时仍然接受-mno-sse。 (与MSVC不同,通常gcc和clang拒绝未启用指令的内在函数。)有趣的是,gcc甚至在其asm输出中发出rep nop,而其他三个发出pause。当然,它们会汇编为相同的机器代码。


暂停会在Sandybridge系列上使该超线程的前端闲置大约5个周期,直到Skylake。在Skylake上,英特尔将其增加到约100个周期,以在自旋等待循环中节省更多电量。

另请参阅What is the purpose of the "PAUSE" instruction in x86?