Как вы используете инструкцию сборки паузы в 64-битном коде C ++? - PullRequest
11 голосов
/ 29 апреля 2011

Поскольку встроенная сборка не поддерживается VC ++ 2010 в 64-битном коде, как я могу получить инструкцию pause x86-64 в свой код?Похоже, что это не присуще этому, как и многие другие общие инструкции по сборке (например, __rdtsc(), __cpuid() и т. Д.).

С другой стороны, я хочу, чтобы инструкция помогала в случае использования ожидания ожидания, чтобы (гиперпоточный) ЦП был доступен другим потокам, работающим на указанном ЦП (см .: Performance Insights на сайте intel.com).Инструкция pause очень полезна для этого варианта использования, а также для реализации спин-блокировки, я не могу понять, почему MS не включила ее в качестве встроенной.

Спасибо

Ответы [ 2 ]

14 голосов
/ 29 апреля 2011

Ого, это была очень сложная проблема, но в случае, если кому-то еще нужна инструкция x86-64 pause:

Макрос YieldProcessor() из windows.h расширяется до недокументированного _mm_pause intrinsic, который в конечном итоге расширяется до инструкции pause в 32-битном и 64-битном коде.

Между прочим, это совершенно недокументировано с частичным (и неверным для документации VC ++ 2010) для YieldProcessor () появляется в MSDN.

Вот пример того, из чего блок макросов 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,3 ГГц ЦП).

1 голос
/ 18 августа 2018

Свойство _mm_pause() полностью задокументировано Intel и поддерживается всеми основными компиляторами x86, переносимыми между операционными системами.IDK, если документы MS отсутствовали в прошлом, или если вы только что пропустили его, ~ 7 лет.

#include <immintrin.h> и используйте его.(Или для древних компиляторов #include <emmintrin.h> для SSE2).

#include <immintrin.h>

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

компилируется в этот ассемблер на всех 4 файлах gcc / clang / ICC / MSVC ( в проводнике компилятора Godbolt ):

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

На процессорах без SSE2 он декодируется как rep nop, что является просто nop. Кроссплатформенная реализация инструкции паузы x86

Gcc даже знает об этом и по-прежнему принимает _mm_pause() при компиляции с -mno-sse.(Обычно gcc и clang отклоняют intriniscs для команд, которые не включены, в отличие от MSVC.) Забавно, что gcc даже выдает rep nop в своем выводе asm, в то время как остальные три выдают pause.Разумеется, они собираются на одном и том же машинном коде.


Пауза бездельничает передний конец этой гиперпотоки в течение примерно 5 циклов в семействе Сэндибридж до Скайлэйка.На Skylake Intel увеличила его до ~ 100 циклов, чтобы сэкономить больше энергии в циклах ожидания вращения.

См. Также Какова цель инструкции PAUSE в x86? .

...