Подтвердить что ты не робот

Как инструкция x86 pause работает в spinlock * и *, может ли она использоваться в других сценариях?

инструкция pause обычно используется в цикле тестирования spinlock, когда какой-то другой поток владеет спин-блокировкой, чтобы смягчить сжатый цикл. Он сказал, что это эквивалентно некоторым инструкциям NOP. Может ли кто-нибудь сказать мне, как именно он работает для оптимизации спин-блокировки? Мне кажется, что даже инструкции NOP являются пустой тратой времени процессора. Будут ли они уменьшать использование ЦП?

Другой вопрос: могу ли я использовать инструкцию паузы для других подобных целей. Например, у меня есть занятый поток, который продолжает сканирование некоторых мест (например, очереди) для извлечения новых узлов; однако, иногда очередь пуста, и поток оправдывает трату времени процессора. спать поток и разбудить его другими потоками может быть вариант, однако поток критический, поэтому я не хочу, чтобы он спал. Может ли приостановить работу с инструкциями для уменьшения использования ЦП? В настоящее время он использует 100% процессор физического ядра?

Спасибо.

4b9b3361

Ответ 1

PAUSE уведомляет CPU о том, что это цикл ожидания спинблока, так что доступ к памяти и кэш-памяти может быть оптимизирован. См. Также инструкцию pause в x86 для получения более подробной информации об избежании ошибочной спекуляции в памяти при выходе из цикла вращения.

PAUSE может фактически остановить процессор в течение некоторого времени, чтобы сэкономить электроэнергию. Старые процессоры декодируют его как REP NOP, поэтому вам не нужно проверять, поддерживается ли оно. Старые процессоры просто ничего не делают (NOP) как можно быстрее.

См. также https://software.intel.com/en-us/articles/benefitting-power-and-performance-sleep-loops


Обновление: я не думаю, что рекомендуется использовать PAUSE в проверке очередей, если вы не сделаете свою очередь в виде спин-блокировки (и нет очевидного способа сделать это).

Спиннинг в течение очень долгого времени по-прежнему очень плох, даже с PAUSE.

Ответ 2

Процессор подвергается серьезному снижению производительности при выходе цикл, потому что он обнаруживает возможное нарушение порядка памяти. Инструкция PAUSE дает подсказку процессору, что кодовая последовательность представляет собой цикл ожидания ожидания. процессор использует эту подсказку, чтобы избежать нарушения порядка памяти в большинстве ситуаций, что значительно повышает производительность процессора. По этой причине рекомендуется что инструкция PAUSE должна быть помещена во все циклы ожидания ожидания. Дополнительная функция инструкции PAUSE - уменьшить мощность, потребляемую процессорами Intel.

[источник: руководство Intel]

Ответ 3

Инструкция PAUSE также используется в процессорах с гиперпотоками, чтобы уменьшить влияние производительности на другие гиперпотоки, возможно, отказавшись от них больше времени процессора.

В приведенной ниже статье Intel описывается это, и неудивительно рекомендует избегать циклов ожидания ожидания на таких процессорах: https://software.intel.com/en-us/articles/long-duration-spin-wait-loops-on-hyper-threading-technology-enabled-intel-processors

Ответ 4

Intel рекомендует только использовать инструкции PAUSE, когда цикл вращения очень короткий.

Как я понял из ваших вопросов, ожидания в вашем случае очень длинные. В этом случае спин-петли не рекомендуется.

Вы написали, что у вас есть "поток, который продолжает сканировать некоторые места (например, очередь) для извлечения новых узлов".

В таком случае Intel рекомендует использовать функции API синхронизации для вашей операционной системы. Например, вы можете создать событие, когда в очереди появится новый node, и просто подождите это событие, используя WaitForSingleObject(Handle, INFINITE). Очередь вызовет это событие всякий раз, когда появится новый node.

В соответствии с Руководством по оптимизации Intel команда PAUSE обычно используется с потоками программного обеспечения, выполняемыми на двух логических процессорах, расположенных в одном и том же ядре процессора, ожидая освобождения блокировки. Такие короткие циклы ожидания имеют тенденцию длиться между десятками и несколькими сотнями циклов (т.е. 20-500 циклов ЦП), поэтому с точки зрения производительности более полезно ждать, занимая процессор, чем уступая ОС.

500 циклов процессора на процессоре Core i7 7700K с тактовой частотой 4500 МГц составляет 0,0000001 секунд, то есть 1/10000000 секунд секунды: процессор может составлять 10 миллионов раз в секунду в этом цикле 500 циклов процессора.

Как вы видите, эта инструкция PAUSE рассчитана на очень короткие промежутки времени.

С другой стороны, каждый вызов функции API, такой как Sleep(), испытывает дорогостоящую стоимость контекстного переключателя, который может быть 10000+ циклов; он также страдает от стоимости кольца 3 до 0 переходов, которые могут быть 1000+ циклов.

Если количество потоков больше, тогда ядра процессора (умноженные на функцию гиперпотока, если они есть) доступны, и поток будет переключен на другой в середине критического раздела, ожидая критической секции из другого потока, действительно выполняйте looong, как минимум 10000+ циклов, поэтому команда PAUSE будет бесполезной.

Для получения дополнительной информации см. следующие статьи:

Когда ожидается, что цикл ожидания будет длиться тысячи циклов или больше, предпочтительнее перейти к операционной системе, вызвав одну из функций API синхронизации ОС, такую ​​как WaitForSingleObject в ОС Windows.

Как вывод: в вашем сценарии команда PAUSE не будет лучшим выбором, так как ваше время ожидания длинное, а PAUSE предназначено для очень коротких циклов. PAUSE - всего 131 цикл SkyWell или более поздних процессоров. Например, это просто или 31.19ns на процессоре Intel Core i7-7700K @4.20GHz Lake Kaby.

На более ранних процессорах, таких как Haswell, у меня около 9 циклов. Это 2,81ns на Intel Core i5-4430 @3GHz. Таким образом, для длинных циклов лучше отказаться от управления другими потоками, используя функции API синхронизации ОС, чем занимать CPU с помощью цикла PAUSE.