Имеет ли смысл использовать инструкцию LFENCE на процессорах x86/x86 64?

часто в Интернете я нахожу, что LFENCE не имеет смысла в процессорах x86, т. е. он ничего не делает, поэтому вместо MFENCE мы можем абсолютно безболезненно использовать SFENCE, потому что MFENCE = SFENCE + LFENCE = SFENCE + NOP = SFENCE.

но если LFENCE не имеет смысла, тогда почему у нас есть четыре подхода для последовательной согласованности в x86 / x86_64:

  1. LOAD (без забора) и STORE + MFENCE
  2. LOAD (без забор) и LOCK XCHG
  3. MFENCE + LOAD и STORE (без забора)
  4. 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!