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

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

Хорошо, я читал следующие Qs из SO относительно заграждений CPU x86 (LFENCE, SFENCE и MFENCE):

и

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

С++ 11:

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

x86/x86_64:

1. Последовательность получения-освобождения:. Тогда важно понять, что в x86 для доступа к обычной ОЗУ (по умолчанию помечен как WB - Write Back и тот же эффект с WT (Write Throught) или UC (Uncacheable)) с помощью asm MOV без каких-либо дополнительных команд автоматически обеспечивает порядок памяти для согласования с принятием-освобождением - 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, но и С++ - компилятор может переупорядочить операции с памятью, и все 6 барьеров памяти всегда влияют на компилятор С++ независимо от архитектуры ЦП.

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

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

  • LOAD (без забора) и STORE + MFENCE
  • LOAD (без забора) и LOCK XCHG
  • MFENCE + LOAD и STORE (без забора)
  • LOCK XADD (0) и STORE (без забора)

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

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

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

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

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

  • Если мы отмечаем память в Таблице страниц как Write Combined (ioremap_wc() в POSIX), то автоматически сохраняет только Consquency Consquency, и мы должны действовать как в следующем абзаце.

  • См. ответ на мой вопрос: fooobar.com/info/160656/...

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

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

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

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

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

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

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

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

Да.

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

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

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

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

  • Обеспечить последовательную согласованность оперативной памяти с кэшем кэша записи
  • Чтобы обеспечить согласованность получения и выпуска в исключениях правила: ОЗУ с записью Комбинированное кеширование, для операций записи, выполняемых с помощью команды CLFLUSH, и для команд Non-Temporal 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