Имеет ли смысл использовать инструкцию LFENCE на процессорах x86/x86 64?
часто в Интернете я нахожу, что LFENCE
не имеет смысла в процессорах x86, т. е. он ничего не делает, поэтому вместо MFENCE
мы можем абсолютно безболезненно использовать SFENCE
, потому что MFENCE
= SFENCE
+ LFENCE
= SFENCE
+ NOP
= SFENCE
.
но если LFENCE
не имеет смысла, тогда почему у нас есть четыре подхода для последовательной согласованности в x86 / x86_64:
-
LOAD
(без забора) иSTORE
+MFENCE
-
LOAD
(без забор) иLOCK XCHG
-
MFENCE
+LOAD
иSTORE
(без забора) -
LOCK XADD
( 0 ) иSTORE
(без забора)
Взято отсюда:http://www.cl.cam.ac.uk / ~pes20/cpp/cpp0xmappings.html
а также выступления Херба Саттера на странице 34 внизу: https://skydrive.live.com/view.aspx?resid=4E86B0CF20EF15AD!24884&app=WordPdf&wdo=2&authkey=!AMtj_EflYn2507c
если LFENCE
ничего не делал, тогда подход (3) имел бы следующие значения: SFENCE + LOAD and STORE (without fence)
, но нет никакого смысла делать SFENCE
до LOAD
. Т. е. если LFENCE
ничего не делает , подход (3) не имеет смысла.
имеет ли смысл инструкция LFENCE
в процессорах архитектуры x86/x86_64 с?
ответ:
1. LFENCE
требуется в случаях, которые описаны в принятом ответе, ниже.
2. подход (3) следует рассматривать не самостоятельно, а в сочетании с предыдущим командам. Например, подход (3):
MFENCE
MOV reg, [addr1] // LOAD-1
MOV [addr2], reg //STORE-1
MFENCE
MOV reg, [addr1] // LOAD-2
MOV [addr2], reg //STORE-2
мы можем переписать код подхода (3) следующим образом:
SFENCE
MOV reg, [addr1] // LOAD-1
MOV [addr2], reg //STORE-1
SFENCE
MOV reg, [addr1] // LOAD-2
MOV [addr2], reg //STORE-2
и здесь SFENCE
имеет смысл предотвратить переупорядочивание магазина-1 и груза-2. Для этого после STORE-1 команда SFENCE
промывает хранилище-буфер.
3 ответов
итог (TL; DR):LFENCE
в одиночку действительно кажется бесполезным для упорядочения памяти, однако это не делает SFENCE
заменить на MFENCE
. "Арифметическая" логика в вопросе неприменима.
вот выдержка из руководство разработчиков программного обеспечения Intel, Том 3, раздел 8.2.2 (издание 325384-052US сентября 2014 года), то же самое, что я использовал в еще один ответ
- читает не переупорядочен с другими чтениями.
- записи не переупорядочиваются со старыми чтениями.
- записи в память не переупорядочиваются с другими записями, за следующими исключениями:
- пишет выполненный с инструкцией CLFLUSH;
- потоковые магазины (записи), выполняемые с помощью инструкций не временного перемещения (MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS и MOVNTPD); и
- строковые операции (см. раздел 8.2.4.1).
- чтение может быть переупорядочено со старыми записями в разные места, но не со старыми записями в одно и то же место.
- чтение и запись не могут быть переупорядочены с помощью инструкций ввода-вывода, заблокированных инструкций или инструкций сериализации.
- чтение не может пройти более ранние инструкции LFENCE и MFENCE.
- записи не могут пройти более ранние инструкции LFENCE, SFENCE и MFENCE.
- инструкции LFENCE не могут пройти раньше читает.
- инструкции SFENCE не могут пройти более ранние записи.
- инструкции MFENCE не могут проходить более ранние чтения или записи.
отсюда следует, что:
-
MFENCE
полная загородка памяти для всех деятельностей на всех типах памяти, ли non-temporal или не. -
SFENCE
только мешает перестройке пишет (в другой терминологии, это StoreStore барьер), и это только полезно вместе с нестационарными хранилищами и другими инструкциями, перечисленными в качестве исключений. -
LFENCE
предотвращает переупорядочивание чтений с последующими чтениями и записями (т. е. сочетает барьеры LoadLoad и LoadStore). Однако первые две пули говорят, что барьеры LoadLoad и LoadStore всегда на месте, без исключений. ПоэтомуLFENCE
один бесполезен для упорядочения памяти.
чтобы поддержать последнее утверждение, Я посмотрел все места, где LFENCE
упоминается во всех 3 Тома руководства Intel, и не нашел ни одного, который бы сказал, что LFENCE
требуется для согласованности памяти. Даже MOVNTDQA
- единственная инструкция не временной нагрузки до сих пор-упоминает MFENCE
а не LFENCE
.
обновление: см. ответы на почему (или нет?) SFENCE + lfence эквивалентно MFENCE? для правильных ответов на догадки ниже
ли MFENCE
эквивалентно "сумме" других двух заборов или нет, это сложно вопрос. На первый взгляд, среди трех инструкций забора только MFENCE
обеспечивает StoreLoad барьер, т. е. предотвращает переупорядочение операций чтения с предыдущими пишет. Однако правильный ответ требует знать больше, чем вышеуказанные правила; а именно, важно, чтобы все инструкции забора были упорядочены относительно друг друга. Это делает SFENCE LFENCE
последовательность более мощная, чем простое объединение отдельных эффектов: эта последовательность также предотвращает переупорядочение загрузки хранилища (потому что нагрузки не могут пройти LFENCE
, которым не могу пройти SFENCE
, который не может пройти магазины) и, таким образом, представляет собой полный забор памяти (но также см. Примечание (*) ниже). Обратите внимание, однако, что порядок имеет значение здесь, и LFENCE SFENCE
последовательность не имеет такого же эффекта синергии.
однако, пока можно сказать, что MFENCE ~ SFENCE LFENCE
и LFENCE ~ NOP
, это не значит MFENCE ~ SFENCE
. Я намеренно использую эквивалентность ( ~ ), а не равенство ( = ), чтобы подчеркнуть, что арифметические правила здесь не применяются. Взаимный эффект SFENCE
затем LFENCE
делает разница; даже если нагрузки не переупорядочены друг с другом, LFENCE
необходимо предотвратить переупорядочивать нагрузок с SFENCE
.
(*) все еще может быть правильным сказать, что MFENCE
сильнее, чем сочетание двух других заборов. В частности, Примечание CLFLUSH
инструкция в томе 2 руководства Intel говорит, что"CLFLUSH
заказывается только MFENCE
инструкция. Не гарантировано быть приказанным любыми другими ограждать или сериализируя инструкциями или другой CLFLUSH
инструкция."
(Update,clflush
теперь определяется как строго упорядоченный (как обычный магазин, поэтому вам нужно только mfence
если вы хотите заблокировать позже нагрузки), но clflushopt
слабо приказано, но может быть огорожено sfence
.)
рассмотрим следующий сценарий - это критический случай, когда выполнение спекулятивной нагрузки теоретически может нанести ущерб последовательной согласованности
первоначально [x]=[y]=0
CPU0: CPU1:
store [x]<--1 store [y]<--1
load r1<--[y] load r2<--[x]
поскольку x86 позволяет переупорядочивать нагрузки с более ранними хранилищами по разным адресам, обе нагрузки могут возвращать 0. Добавление только lfence после каждого магазина не предотвратит этого, поскольку они только предотвращают переупорядочивание в том же контексте, но поскольку магазины отправляются после выхода на пенсию, вы может иметь как lfences, так и фиксацию обеих нагрузок до выполнения и наблюдения хранилищ.
An mfence С другой стороны, заставит магазины выполнять, и только тогда разрешить загрузку, поэтому вы увидите обновленные данные по крайней мере в одном контексте.
по состоянию на sfences - как указано в комментарии, теоретически он недостаточно силен, чтобы предотвратить переупорядочение нагрузки над ним, поэтому он может все еще читать устаревшие данные. Пока это правда, что касается официальных правил упорядочения памяти, я считаю, что текущая реализация x86 uarch делает ее немного сильнее (хотя и не обязуется делать это в будущем, я думаю). Согласно описание:
из-за сильной модели заказа x86 буфер загрузки отслеживается по связности трафика. Удаленное хранилище должно аннулировать все остальные копии строки кэша. Если строка кэша считывается загрузкой, а затем признана недействительной удаленной магазин, нагрузка необходимо отменить, в виду того что она потенциально считывать недопустимые данные. Модель памяти x86 не требует слежу за буфером хранилища.
поэтому любая нагрузка, еще не зафиксированная в машине, должна быть отслеживаемой магазинами из других ядер, тем самым делая эффективное время наблюдения нагрузки на commit точка, а не исполнение point (который действительно не в порядке и, возможно, был выполнен много выше.) Фиксация выполняется в порядке, и поэтому нагрузка должна соблюдаться после предыдущих инструкций - что делает lfences практически бесполезными, как я сказал выше в комментариях, так как согласованность может поддерживаться таким же образом без них. Это в основном спекуляции, пытаясь объяснить общую концепцию, что lfences бессмысленны в x86 - я не совсем уверен, где она возникла, и если есть другие соображения под рукой - был бы рад любому эксперту одобрить / оспорить это теория.
все вышесказанное относится только к типам WB mem, конечно
конечно, это делает sence!
LFENCE
из Intel datasheet:
выполняет операцию сериализации всех инструкций по загрузке из памяти это было сделано до инструкции LFENCE. Эта сериализация деятельность гарантирует что каждая инструкция нагрузки которая предшествует внутри заказ программы инструкция LFENCE глобально видна перед любым инструкция нагрузки, следующая за инструкцией LFENCE, глобально видимый.
память написать инструкцию, как MOV
являются атомарными, если они правильно выровнены. Но эта инструкция обычно выполняется в кэше CPU и не будет глобально видна в данный момент для всех других потоков, потому что memory LFENCE/SFENCE or MFENCE
должен быть предварительно сформирован.
типичный случай:
если thread writer разблокирует область памяти с помощью инструкции записи, такой как выровненная память MOV
, Так что нет LOCK
префикс инструкция используется, чем строка кэша, где был peformed MOV
должен быть видимых в ближайшем будущем для всех других потоков. LFENCE
обеспечить к читателю потока, который также все другие строки кэша из thread writer являются глобальными visibe!