Когда требуются инструкции x86 LFENCE, SFENCE и MFENCE?

Хорошо, я читал следующие вопросы от SO относительно заборов процессора x86 (LFENCE, SFENCE а также MFENCE):

а также:

и я должен быть честным, я все еще не совсем уверен, когда требуется забор. Я пытаюсь понять с точки зрения удаления полностью взорванных замков и пытаюсь использовать более мелкозернистую блокировку через заборы, чтобы минимизировать задержки.

Во-первых, вот два конкретных вопроса, которые я не понимаю:

Иногда при создании хранилища процессор записывает в свой буфер хранилища вместо кэша L1. Я, однако, не понимаю условия, на которых процессор будет делать это?

CPU2 может захотеть загрузить значение, которое было записано в буфер хранилища CPU1. Насколько я понимаю, проблема в том, что CPU2 не может увидеть новое значение в буфере хранилища CPU1. Почему протокол MESI не может просто включать буферы очистки в качестве части своего протокола?

В более общем плане, может кто-нибудь попытаться описать общий сценарий и помочь объяснить, когда LFENCE / MFENCE а также SFENCE инструкции необходимы?

NB. Одной из проблем, связанных с чтением этой темы, является количество статей, написанных "в общем" для архитектур с несколькими процессорами, когда меня интересует только архитектура Intel x86-64.

1 ответ

Самый простой ответ: вы должны использовать один из 3 заборов (LFENCE, SFENCE, MFENCE) обеспечить одно из 6 данных согласованности:

  • расслабленный
  • потреблять
  • приобрести
  • Релиз
  • Приобретать-релиз
  • последовательный

C++11:

Первоначально вы должны рассмотреть эту проблему с точки зрения степени порядка доступа к памяти, которая хорошо документирована и стандартизирована в C++11. Вы должны прочитать сначала: http://en.cppreference.com/w/cpp/atomic/memory_order

x86 / x86_64:

1. Согласованность получения-выпуска. Затем важно понимать, что в x86 доступ к обычной оперативной памяти (помеченный по умолчанию как WB - Write Back, и тот же эффект с WT (Write Throught) или UC (Uncacheable)) используя асм MOV без каких-либо дополнительных команд автоматически обеспечивает порядок памяти для Acquire-Release Consistency - std::memory_order_acq_rel, Т.е. для этой памяти имеет смысл использовать только std::memory_order_seq_cst только для обеспечения последовательной согласованности. Т.е. когда вы используете: std::memory_order_relaxed или же std::memory_order_acq_rel тогда скомпилированный ассемблерный код для std::atomic::store() (или же std::atomic::load()) будет так же - только MOV без всяких L/S/MFENCE,

Примечание: Но вы должны знать, что не только CPU, но и C++-компилятор могут переупорядочивать операции с памятью, и все 6 барьеров памяти всегда влияют на C++-компилятор независимо от архитектуры CPU.

Затем вы должны знать, как его можно скомпилировать из C++ в ASM (машинный код) или как написать его на ассемблере. Чтобы обеспечить любую непротиворечивость, исключающую последовательную, вы можете просто написать MOV, например MOV reg, [addr] а также MOV [addr], reg и т.п.

2. Последовательная согласованность: но для обеспечения последовательной согласованности вы должны использовать неявную (LOCK) или явные заборы (L / S / MFENCE), как описано здесь: Почему GCC не использует LOAD(без ограждения) и STORE+SFENCE для последовательной согласованности?

  1. LOAD (без забора) и STORE + MFENCE
  2. LOAD (без забора) и LOCK XCHG
  3. MFENCE + LOAD а также STORE (без забора)
  4. LOCK XADD (0) и STORE (без забора)

Например, GCC использует 1, а MSVC использует 2. (Но вы должны знать, что в MSVS2012 есть ошибка: требует ли семантика `std::memory_order_acquire` инструкций процессора для x86/x86_64?)

Затем вы можете прочитать Херб Саттер, ваша ссылка: https://onedrive.live.com/view.aspx?resid=4E86B0CF20EF15AD!24884&app=WordPdf&authkey=!AMtj_EflYn2507c

Исключение из правила:

Это правило верно для доступа с помощью MOV в обычную оперативную память, помеченную по умолчанию как WB - Write Back. Память отмечается в таблице страниц, в каждом PTE (номер таблицы страниц) для каждой страницы (4 КБ непрерывной памяти).

Но есть некоторые исключения:

  1. Если мы помечаем память в Page Table как Write Combined (ioremap_wc() в POSIX), то автоматически предоставляет только Acquire Consistency, и мы должны действовать, как в следующем абзаце.

  2. Смотрите ответ на мой вопрос: /questions/24667295/imeyutsya-li-v-x86-sse-instruktsiyah-poryadok-avtomaticheskogo-vyipuska-polucheniya/24667311#24667311

  • Записи в память не переупорядочиваются с другими записями, за следующими исключениями:
    • запись выполняется с помощью инструкции CLFLUSH;
    • потоковые хранилища (записи), выполняемые с помощью временных инструкций перемещения (MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS и MOVNTPD); а также
    • строковые операции (см. раздел 8.2.4.1).

В обоих случаях 1 и 2 вы должны использовать дополнительные SFENCE между двумя записями на один и тот же адрес, даже если вы хотите получить согласованность при получении, поскольку здесь автоматически предоставляется только согласование при получении, и вы должны выполнить команду Release (SFENCE) сам.

Ответьте на два вопроса:

Иногда при создании хранилища процессор записывает в свой буфер хранилища вместо кэша L1. Я, однако, не понимаю условия, на которых процессор будет делать это?

С точки зрения пользователя кэш L1 и Store Buffer действуют по-разному. L1 быстро, но Store-Buffer быстрее.

  • Store-Buffer - это простая очередь, в которой хранятся только записи, и которую нельзя переупорядочить - она ​​предназначена для увеличения производительности и скрытия задержки доступа к кэшу (L1 - 1 нс, L2 - 3 нс, L3 - 10 нс) (CPU-Core) думаю, что запись сохранена в кэш и выполняет следующую команду, но в то же время ваши записи будут сохранены только в Store-Buffer и будут сохранены в кэш L1/2/3 позже), т.е. CPU-Core не нужен ждать, когда записи будут сохранены в кэш.

  • Кэш L1/2/3 - выглядит как прозрачный ассоциированный массив (адрес - значение). Он быстрый, но не самый быстрый, потому что x86 автоматически обеспечивает согласованность при получении-выпуске с использованием согласованного с кэшем протокола MESIF / MOESI. Это сделано для более простого многопоточного программирования, но снижает производительность. (Поистине, мы можем использовать алгоритмы и структуры данных без записи без использования когерентного кэша, т.е. без MESIF/MOESI, например, через PCI Express). Протоколы MESIF/MOESI работают через QPI, который соединяет ядра в процессоре и ядра между различными процессорами в многопроцессорных системах ( ccNUMA).

CPU2 может захотеть загрузить значение, которое было записано в буфер хранилища CPU1. Насколько я понимаю, проблема в том, что CPU2 не может увидеть новое значение в буфере хранилища CPU1.

Да.

Почему протокол MESI не может просто включать буферы очистки в качестве части своего протокола?

Протокол MESI не может просто включать буферы очистки в качестве части своего протокола, потому что:

  • Протоколы MESI/MOESI/MESIF не связаны с Store-Buffer и не знают об этом.
  • Автоматическая очистка Store Buffer при каждой записи уменьшит производительность и сделает ее бесполезной.
  • Ручная очистка буфера хранилища на всех удаленных ядрах ЦП (мы не знаем, в каком хранилище буфера Core содержится требуемая запись) с помощью какой-либо команды - снизит производительность (в 8 ЦП x 15 ядер = 120 ядер одновременно, очистить хранилище -Буфер - это ужасно)

Но ручная очистка Store Buffer на текущем CPU-Core - да, вы можете сделать это, выполнив SFENCE команда. Ты можешь использовать SFENCE в двух случаях:

  • Обеспечение последовательной согласованности в оперативной памяти с возможностью кэширования с обратной записью
  • Обеспечение согласованности Acquire-Release для исключений из правила: ОЗУ с возможностью записи в комбинированную кэш-память, для записей, выполняемых с помощью инструкции CLFLUSH, и для невременных команд SSE/AVX

Замечания:

Нужны ли нам LFENCE в каких случаях на x86/x86_64? - вопрос не всегда понятен: имеет ли смысл инструкция LFENCE в процессорах x86/x86_64?

Другая платформа:

Затем вы можете читать, как теоретически (для сферического процессора в вакууме) с Store-Buffer и Invalidate-Queue, по вашей ссылке: http://www.puppetmastertrading.com/images/hwViewForSwHackers.pdf

И как вы можете обеспечить последовательную согласованность на других платформах, не только с L/S/MFENCE и LOCK, но и с LL / SC: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

Другие вопросы по тегам