Есть ли у блокировки xchg такое же поведение, как у mfence?
Что мне интересно, если lock xchg
будет иметь подобное поведение mfence
с точки зрения одного потока, обращающегося к области памяти, которая видоизменяется (скажем, наугад) другими потоками. Гарантирует ли это, что я получаю самую актуальную стоимость? Из памяти чтения / записи инструкции, которые следуют после?
Причина моего замешательства:
8.2.2 "Чтение или запись не могут быть переупорядочены с помощью инструкций ввода / вывода, заблокированных инструкций или инструкций сериализации".
-Intel 64 Developers Manual Vol. 3
Это относится ко всем потокам?
mfence
состояния:
Выполняет сериализацию для всех команд загрузки из памяти и хранения в память, которые были выполнены до инструкции MFENCE. Эта операция сериализации гарантирует, что каждая инструкция загрузки и сохранения, которая предшествует в программном порядке команде MFENCE, будет видна глобально, прежде чем любая команда загрузки или сохранения, которая следует за инструкцией MFENCE, станет видимой глобально. Инструкция MFENCE упорядочена в отношении всех инструкций загрузки и хранения, других инструкций MFENCE, любых инструкций SFENCE и LFENCE и любых инструкций сериализации (таких как инструкция CPUID).
-Intel 64 Пособие для разработчиков Том 3А
Это звучит как более сильная гарантия. Как это звучит как mfence
почти очищает буфер записи или, по крайней мере, обращается к буферу записи и другим ядрам, чтобы гарантировать, что мои будущие загрузки / хранилища будут обновлены.
При выполнении эталонных тестов обе инструкции занимают порядка ~100 циклов. Так что я не вижу такой большой разницы в любом случае.
В первую очередь я просто запутался. Я инструкции, основанные вокруг lock
используется в мьютексах, но тогда они не содержат заборов памяти. Затем я вижу программирование без блокировки, которое использует заборы памяти, но не блокирует. Я понимаю, что у AMD64 очень сильная модель памяти, но устаревшие значения могут сохраняться в кеше. Если lock
не ведет себя так же, как mfence
тогда как мьютексы помогают вам увидеть самое последнее значение?
1 ответ
Я считаю, что ваш вопрос такой же, как вопрос mfence
имеет ту же семантику барьера, что и lock
инструкции с префиксом на x86, или если он предоставляет меньше 1 или дополнительные гарантии в некоторых случаях.
Мой лучший лучший ответ: намерение Intel и что документация ISA гарантирует, что mfence
а также lock
Инструкции ed обеспечивают ту же семантику ограждения, но из-за недосмотра реализации, mfence
фактически обеспечивает более сильную семантику ограждения на новейшем оборудовании (по крайней мере, у Haswell). Особенно, mfence
может ограничить последующую невременную загрузку из области памяти типа WC, в то время как lock
Редакции инструкции нет.
Мы знаем это, потому что Intel сообщает нам об этом с ошибками процессора, такими как HSD162 (Haswell) и SKL155 (Skylake), которые говорят нам, что заблокированные инструкции не ограничивают последующее невременное чтение из WC-памяти:
MOVNTDQA из памяти WC может пройти ранее заблокированные инструкции
Проблема: может показаться, что выполнение (V)MOVNTDQA (инструкции загрузки потоковой передачи), которая загружается из памяти WC (комбинирование записи), передает ранее заблокированную инструкцию, которая обращается к другой строке кэша.
Вывод: Программное обеспечение, которое ожидает блокировку для защиты от последующих (V) инструкций MOVNTDQA, может работать неправильно.
Обход проблемы: не выявлено. Программное обеспечение, которое полагается на заблокированную инструкцию для защиты последующих выполнений (V) MOVNTDQA, должно вставить инструкцию MFENCE между заблокированной инструкцией и последующей (V) инструкцией MOVNTDQA.
Исходя из этого, мы можем определить, что (1) Intel, вероятно, предполагала, что заблокированные инструкции ограничивают загрузку NT из памяти типа WC, иначе это не будет ошибкой 0,5 и (2), что заблокированные инструкции на самом деле этого не делают, и Intel не могла или решила не исправлять это с помощью обновления микрокода, и mfence
рекомендуется вместо
В Скайлэйке, mfence
фактически потерял свою дополнительную способность ограждения относительно загрузок NT, согласно SKL079: MOVNTDQA из памяти WC может пройти более ранние инструкции MFENCE - этот текст в значительной степени совпадает с текстом lock
-инструкция исправления, но относится к mfence
, Тем не менее, состояние этой ошибки: "Возможно, BIOS содержит обходной путь для этой ошибки", что, как правило, говорит Intel "обновление микрокода решает эту проблему".
Эта последовательность ошибок, возможно, может быть объяснена сроками: ошибки Haswell появляются только в начале 2016 года, спустя годы после выпуска этого процессора, поэтому мы можем предположить, что проблема дошла до Intel за некоторое умеренное время. В этот момент Скайлэйк почти наверняка был уже в дикой природе, с явно менее консервативным mfence
реализация, которая также не ограничивала загрузку NT в областях памяти типа WC. Исправление того, как заблокированные инструкции работают вплоть до Haswell, было, вероятно, либо невозможным, либо дорогостоящим из-за их широкого использования, но был необходим какой-то способ, чтобы оградить загрузку NT. mfence
по-видимому, уже сделал работу на Haswell, и Skylake будет исправлена так, чтобы mfence
работал там тоже.
Это на самом деле не объясняет, почему SKL079 (mfence
один) появился в январе 2016 года, почти за два года до SKL155 (locked
один) появился в конце 2017 года, или почему последний появился так много после идентичных ошибок Haswell, однако.
Можно предположить, что Intel будет делать в будущем. Так как они не смогли / не захотели изменить lock
Инструкция для Haswell через Skylake, представляющая сотни миллионов (миллиардов?) развернутых микросхем, никогда не сможет гарантировать, что заблокированные инструкции ограничивают нагрузку NT, поэтому они могут рассмотреть возможность сделать это документированным, спроектированным поведением в будущем. Или они могут обновить заблокированные инструкции, поэтому они блокируют такие операции чтения, но с практической точки зрения вы не можете полагаться на это, вероятно, в течение десятилетия или более, пока микросхемы с текущим поведением без ограждения практически не выйдут из обращения.
Питер Кордес написал немного о Скайлэйке mfence
изменить в конце этого ответа.
Оставшаяся часть этого ответа - мой первоначальный ответ до того, как я узнал об ошибках, и который оставлен в основном для исторического интереса.
Старый ответ
Мое обоснованное предположение в ответ таково, что mfence
обеспечивает дополнительную функциональность барьера: между доступами с использованием слабо упорядоченных инструкций (например, хранилищами NT) и, возможно, между доступами со слабоупорядоченными областями (например, памятью типа WC).
Тем не менее, это всего лишь обоснованное предположение, и вы найдете подробности моего расследования ниже.
подробности
Документация
Не совсем ясно, в какой степени mfence
отличается от того, что предусмотрено lock
инструкция с префиксом (в том числе xchg
с операндом памяти, который неявно заблокирован).
Я думаю, что можно с уверенностью сказать, что это касается исключительно областей памяти с обратной записью и не требует каких-либо невременных обращений, mfence
обеспечивает ту же семантику заказа, что и lock
операция с префиксом.
Что открыто для обсуждения mfence
отличается от всех lock
инструкции с префиксом, когда дело доходит до сценариев вне вышеперечисленного, в частности, когда доступ включает в себя области, отличные от областей WB, или когда задействованы невременные (потоковые) операции.
Например, вы можете найти некоторые предложения (например, здесь или здесь), которые mfence
подразумевает семантику сильного барьера, когда задействованы операции типа WC (например, хранилища NT).
Например, цитируя доктора Маккальпина в этой теме (выделение добавлено):
Инструкция по забору необходима только для того, чтобы быть абсолютно уверенным, что все временные хранилища видны перед последующим "обычным" хранилищем. Наиболее очевидный случай, когда это имеет значение, - это параллельный код, где "барьер" в конце параллельной области может включать "обычное" хранилище. Без ограничений процессор мог бы по-прежнему изменять данные в буферах записи-объединения, но проходить через барьер и позволять другим процессорам считывать "устаревшие" копии данных записи-объединения. Этот сценарий может также применяться к одному потоку, который ОС переносит из одного ядра в другое (не уверен в этом случае).
Я не могу вспомнить подробные рассуждения (еще недостаточно кофе сегодня утром), но инструкция, которую вы хотите использовать после невременных магазинов, - это MFENCE. Согласно разделу 8.2.5 тома 3 SWDM, MFENCE является единственной инструкцией по ограждению, которая предотвращает выполнение как последующих загрузок, так и последующих хранилищ до завершения ограждения. Я удивлен, что это не упомянуто в Разделе 11.3.1, который говорит вам, как важно вручную обеспечить согласованность при использовании комбинирования записи, но не говорит вам, как это сделать!
Давайте посмотрим на упомянутый раздел 8.2.5 Intel SDM:
Усиление или ослабление модели упорядочения памяти
Архитектуры Intel 64 и IA-32 предоставляют несколько механизмов для усиления или ослабления модели упорядочения памяти для обработки особых ситуаций программирования. Эти механизмы включают в себя:
• Инструкции ввода / вывода, инструкции по блокировке, префикс LOCK и инструкции по сериализации усиливают упорядочение процессора.
• Инструкция SFENCE (введенная в архитектуру IA-32 в процессоре Pentium III) и инструкции LFENCE и MFENCE (введенная в процессоре Pentium 4) предоставляют возможности упорядочения памяти и сериализации для определенных типов операций с памятью.
Эти механизмы могут быть использованы следующим образом:
Устройства с отображением в памяти и другие устройства ввода / вывода на шине часто чувствительны к порядку записи в свои буферы ввода / вывода. Команды ввода / вывода могут использоваться для (инструкции IN и OUT) наложения строгого порядка записи на такие обращения следующим образом. Перед выполнением команды ввода / вывода процессор ожидает завершения всех предыдущих инструкций в программе и всех буферизованных записей для их сброса в память. Только выборка инструкций и обход таблиц могут передавать инструкции ввода / вывода. Выполнение последующих инструкций не начинается до тех пор, пока процессор не определит, что инструкция ввода / вывода выполнена.
Механизмы синхронизации в многопроцессорных системах могут зависеть от строгой модели упорядочения памяти. Здесь программа может использовать инструкцию блокировки, такую как инструкция XCHG или префикс LOCK, чтобы гарантировать, что операция чтения-изменения-записи в памяти выполняется атомарно. Операции блокировки обычно работают подобно операциям ввода-вывода в том смысле, что они ожидают завершения всех предыдущих инструкций и всех буферизованных записей, стекающих в память (см. Раздел 8.1.2 "Блокировка шины").
Синхронизация программы также может быть выполнена с инструкциями сериализации (см. Раздел 8.3). Эти инструкции обычно используются на границах критических процедур или задач для принудительного завершения всех предыдущих инструкций перед переходом к новому разделу кода или переключению контекста. Как и команды ввода-вывода и блокировки, процессор ожидает выполнения всех предыдущих инструкций, а все буферизованные записи выводятся в память, прежде чем выполнять команду сериализации.
Команды SFENCE, LFENCE и MFENCE обеспечивают эффективный способ обеспечения загрузки и сохранения порядка памяти между подпрограммами, которые дают плохо упорядоченные результаты, и подпрограммами, которые потребляют эти данные. Функции этих инструкций следующие:
• SFENCE - Сериализует все операции сохранения (записи), которые произошли до выполнения команды SFENCE в потоке команд программы, но не влияет на операции загрузки.
• LFENCE - Сериализует все операции загрузки (чтения), которые произошли до выполнения команды LFENCE в потоке команд программы, но не влияет на операции сохранения.
• MFENCE - Сериализует все операции сохранения и загрузки, которые выполнялись до инструкции MFENCE в потоке команд программы.
Обратите внимание, что инструкции SFENCE, LFENCE и MFENCE обеспечивают более эффективный метод управления упорядочением памяти, чем инструкция CPUID.
Вопреки интерпретации д-ра Маккальпина 2, я вижу этот раздел несколько двусмысленным относительно того, mfence
делает что-то дополнительно. Три раздела, относящиеся к IO, заблокированным инструкциям и инструкциям сериализации, подразумевают, что они обеспечивают полный барьер между операциями с памятью до и после операции. Они не делают никаких исключений для слабо упорядоченной памяти, и в случае инструкций ввода-вывода можно было бы также предположить, что они должны работать согласованно со слабо упорядоченными областями памяти, поскольку они часто используются для ввода-вывода.
Тогда раздел для FENCE
В инструкциях в нем явно упоминаются слабые области памяти: "Инструкции SFENCE, LFENCE и MFENCE ** обеспечивают эффективный способ обеспечения загрузки и сохранения порядка памяти между подпрограммами, которые производят слабо упорядоченные результаты, и подпрограммами, которые потребляют эти данные".
Читаем ли мы между строк и понимаем ли это, что это единственные инструкции, которые выполняют это, и что ранее упомянутые методы (включая заблокированные инструкции) не помогают для слабых областей памяти? Мы можем найти некоторую поддержку этой идее, отметив, что инструкции по забору были введены 3 одновременно со слабо упорядоченными не временными инструкциями хранилища, и с помощью текста, подобного тому, который был найден в 11.6.13 Инструкции по подсказкам кэширования, относящиеся конкретно к слабо упорядоченным инструкциям:
Степень, до которой потребитель данных знает, что данные слабо упорядочены, может варьироваться в этих случаях. В результате, команда SFENCE или MFENCE должна использоваться для обеспечения упорядочения между подпрограммами, которые производят слабо упорядоченные данные, и подпрограммами, которые потребляют данные. SFENCE и MFENCE обеспечивают эффективный способ обеспечения порядка, гарантируя, что каждая инструкция сохранения, которая предшествует SFENCE/MFENCE в программном порядке, будет видна глобально перед инструкцией сохранения, которая следует за ограждением.
Опять же, здесь специально указываются инструкции по ограждению, подходящие для ограждения слабо упорядоченных инструкций.
Мы также поддерживаем идею о том, что заблокированная инструкция не может обеспечить барьер между слабо упорядоченными доступами из последнего предложения, уже цитированного выше:
Обратите внимание, что инструкции SFENCE, LFENCE и MFENCE обеспечивают более эффективный метод управления упорядочением памяти, чем инструкция CPUID.
Здесь в основном подразумевается, что FENCE
инструкции по существу заменяют функциональность, ранее предложенную сериализацией cpuid
с точки зрения упорядочения памяти. Однако если lock
инструкции с префиксом обеспечивают такую же барьерную способность, что и cpuid
, это, вероятно, было бы предложенным ранее способом, так как в целом они намного быстрее, чем cpuid
который часто занимает 200 или более циклов. Подразумевается, что были сценарии (вероятно, слабо упорядоченные сценарии), которые lock
инструкции с префиксом не обрабатывались, и где cpuid
и где mfence
теперь предлагается в качестве замены, подразумевая более сильную барьерную семантику, чем lock
инструкции с префиксом.
Тем не менее, мы могли бы интерпретировать некоторые из вышеперечисленных по-другому: обратите внимание, что в контексте инструкций по ограждению часто упоминается, что они представляют собой эффективный способ обеспечения порядка. Таким образом, возможно, что эти инструкции предназначены не для того, чтобы предоставить дополнительные барьеры, а просто для более эффективных барьеров.
В самом деле, sfence
в несколько циклов намного быстрее, чем сериализация инструкций, таких как cpuid
или же lock
-приставленные инструкции, которые обычно состоят из 20 или более циклов. С другой стороны mfence
обычно не быстрее, чем заблокированные инструкции 4, по крайней мере, на современном оборудовании. Тем не менее, он мог бы быть быстрее, когда он был представлен, или на каком-то будущем дизайне, или, возможно, ожидалось, что он будет быстрее, но это не сработало.
Поэтому я не могу дать определенную оценку на основе этих разделов руководства: я думаю, что вы можете привести разумный аргумент, что это может быть истолковано в любом случае.
Далее мы можем посмотреть документацию по различным инструкциям временного хранения в руководстве Intel ISA. Например, в документации для временного магазина movnti
Вы найдете следующую цитату:
Поскольку в протоколе WC используется слабо упорядоченная модель согласованности памяти, операция ограждения, реализованная с помощью инструкции SFENCE или MFENCE, должна использоваться в сочетании с инструкциями MOVNTI, если несколько процессоров могут использовать разные типы памяти для чтения / записи областей памяти назначения.
Часть о том, "если несколько процессоров могут использовать разные типы памяти для чтения / записи областей памяти назначения", меня немного смущает. Я ожидал бы, что это скорее скажет что-то вроде "для обеспечения порядка в глобально видимом порядке записи между инструкциями с использованием слабо упорядоченных подсказок" или что-то в этом роде. Действительно, реальный тип памяти (например, как определено MTTR), вероятно, здесь даже не вступает в игру: проблемы упорядочения могут возникать только в WB-памяти при использовании слабо упорядоченных инструкций.
Спектакль
mfence
Сообщается, что на современных процессорах команда занимает 33 цикла (задержка в спине), основанная на времени командирования Агнера Тумана, но более сложная блокированная команда типа lock cmpxchg
Сообщается, что займет всего 18 циклов.
Если mfence
обеспеченная семантика барьера не более чем lock cmpxchg
последний делает больше работы, и нет явных причин mfence
занять значительно больше времени. Конечно, вы можете утверждать, что lock cmpxchg
просто важнее, чем mfence
и, следовательно, получает больше оптимизации. Этот аргумент ослаблен тем, что все заблокированные инструкции выполняются значительно быстрее, чем mfence
даже редко используемые. Кроме того, вы могли бы представить, что если бы была единственная барьерная реализация, разделяемая всеми lock
инструкции, mfence
будет просто использовать тот же самый, поскольку это самый простой и легкий для проверки.
Так что медленная производительность mfence
является, на мой взгляд, существенным доказательством того, что mfence
делает некоторые дополнительные.
0.5 Это не водонепроницаемый аргумент. Некоторые вещи могут появляться с ошибками, которые, по-видимому, "по замыслу", а не ошибка, такие как popcnt
ложная зависимость от регистра назначения - поэтому некоторые ошибки можно считать формой документации для обновления ожиданий, а не всегда подразумевать аппаратную ошибку.
1 Очевидно, что lock
инструкция с префиксом также выполняет элементарную операцию, которую невозможно достичь только с mfence
, Итак lock
-приставленные инструкции определенно имеют дополнительную функциональность. Поэтому для mfence
чтобы быть полезным, мы ожидаем, что в некоторых сценариях он будет иметь дополнительную семантику барьера или будет работать лучше.
2 Также вполне возможно, что он читал другую версию руководства, где проза отличалась.
3 SFENCE
в SSE, lfence
а также mfence
в SSE2.
4 И часто это медленнее: у Агнера он указан с задержкой 33 цикла на недавнем оборудовании, в то время как заблокированные инструкции обычно составляют около 20 циклов.