Обеспечивает ли модель памяти Intel избыточность SFENCE и LFENCE?

Модель памяти Intel гарантирует:

  • Покупки в магазинах не будут переупорядочены в других магазинах.
  • Заказы на другие грузы не будут переупорядочены.

http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/

Я видел утверждения, что SFENCE избыточен на x86-64 из-за модели памяти Intel, но никогда не LFENCE. Делают ли приведенные выше правила модели памяти избыточными какие-либо инструкции?


person user997112    schedule 21.09.2015    source источник
comment
Эээ, а как насчет заказов Store-Load и Load-Store?   -  person Iwillnotexist Idonotexist    schedule 22.09.2015
comment
@IwillnotexistIdonotexist: MFENCE - это барьер StoreLoad (и все 3 других типа тоже). И да, он вам еще нужен. : P Я не уверен, может ли movNT load / store отображать переупорядочение LoadStore, или если они пропустили отдельную инструкцию LoadStore, исходя из предположения, что вам обычно (всегда?) Нужен барьер StoreLoad каждый раз, когда вам нужен барьер LoadStore. Поскольку он в любом случае влияет только на операции потоковой передачи movnt, это особый случай особого случая, и x86 прекрасно обходится без него. :П   -  person Peter Cordes    schedule 22.09.2015
comment
@PeterCordes В предыдущем ответе я цитировал полный список или разрешенные переупорядочения из Intel SDM. Но то, что я привел в своем комментарии выше, заключается в том, что OP указал, в основном правильно, что переупорядочение Load-Load и Store-Store не происходит. Однако это всего лишь две из четырех возможных комбинаций (две другие комбинации - Load-Store и Store-Load), и эти другие возможности могут возникать, поэтому возникает необходимость в mfence/sfence/lfence.   -  person Iwillnotexist Idonotexist    schedule 22.09.2015
comment
@IwillnotexistIdonotexist: О, интересно, так что LFENCE также является барьером Load-Store, поскольку более поздние хранилища не могут быть глобально видимы до load / lfence. Я предполагаю, что обычно movnt загрузка / сохранение переупорядочиваются таким образом, скорее всего, если адрес загрузки не был доступен до окончания сохранения. Я не слишком внимательно смотрел на LFENCE и предположил, что это просто барьер LoadLoad.   -  person Peter Cordes    schedule 22.09.2015


Ответы (1)


Правильно, LFENCE и SFENCE бесполезны в обычном коде, потому что семантика получения / выпуска x86 для обычных хранилищ делает их избыточными, если вы не используете другие специальные инструкции или типы памяти.

Единственное препятствие, которое имеет значение для нормального кода без блокировки, - это полный барьер (включая StoreLoad) от инструкции locked или медленный MFENCE. Предпочитайте xchg для хранилищ с последовательной согласованностью, а не _3 _ + _ 4_. Загружает и сохраняет единственные инструкции, которые меняются? потому что так быстрее.

Включает ли `xchg`` mfence` без вневременных инструкций ? (да, даже с инструкциями NT, если нет памяти WC.)


Статья Джеффа Прешинга переупорядочение памяти прямо в процессе - это более удобное для чтения описание того же случая, о котором говорится в сообщении Бартоша, когда вам нужен барьер StoreLoad, такой как MFENCE. Подойдет только MFENCE; вы не можете построить MFENCE из SFENCE + LFENCE. (Почему эквивалентно (или нет?) SFENCE + LFENCE в MFENCE?)

Если у вас возникли вопросы после прочтения размещенной вами ссылки, прочитайте другие сообщения Джеффа Прешинга в блоге. Они дали мне хорошее понимание предмета. :) Хотя я думаю, что нашел лакомый кусочек о том, что SFENCE / LFENCE обычно не используются на странице Дуга Ли. В сообщениях Джеффа не учитывались загрузки / магазины NT.


По теме: Когда следует использовать _mm_sfence _mm_lfence и _mm_mfence (мой ответ и ответ @ BeeOnRope хороши. Я написал этот ответ намного раньше, чем этот ответ, поэтому некоторые части этого ответа показывают мою неопытность много лет назад. В моем ответе рассматриваются внутренние особенности C ++ и Порядок памяти во время компиляции C ++, что совсем не то же самое, что порядок памяти во время выполнения в x86 asm. Но вам все равно не нужно _mm_lfence().)


SFENCE имеет значение только при использовании movnt (Non-Temporal) потоковых хранилищ или при работе с областями памяти с типом, отличным от обычного Write-Back. Или с clflushopt, который похож на магазин со слабым порядком. NT-хранилища обходят кеш-память, так как они слабо упорядочены. нормальная модель памяти x86 строго упорядочена, кроме хранилищ NT, WC (объединение записи) память и строковые операции ERMSB (см. ниже)).

LFENCE полезен только для упорядочивания памяти со слабо упорядоченными нагрузками, что очень редко. (Или возможно для заказа LoadStore с регулярными загрузками до NT-магазинов?)

Загрузка NT (movntdqa) из памяти WB все еще строго упорядочены, даже на гипотетическом ЦП будущего, который не игнорирует Подсказка NT; единственный способ выполнять слабоупорядоченную загрузку на x86 - это читать из слабоупорядоченной памяти (WC), и тогда, я думаю, только с movntdqa. Это не происходит случайно в "обычных" программах, поэтому вам нужно беспокоиться об этом, только если вы используете mmap видео RAM или что-то в этом роде.

(Основным вариантом использования lfence является вовсе не упорядочение памяти, а сериализация выполнения инструкций, например, для устранения угроз Spectre или с помощью RDTSC. См. Выполняется ли сериализация LFENCE на процессорах AMD? и боковую панель" связанных вопросов "для этого вопроса.)


Упорядочение памяти в C ++ и его отображение в x86 asm

Пару недель назад мне стало любопытно, и я опубликовал довольно подробный ответ на недавний вопрос: Атомарные операции, std :: atomic‹ ›и порядок записи. Я включил множество ссылок на информацию о модели памяти C ++ и моделях аппаратной памяти.

Если вы пишете на C ++, использование std::atomic<> - отличный способ сообщить компилятору, какие у вас требования к порядку, чтобы он не переупорядочивал ваши операции с памятью во время компиляции. Вы можете и должны использовать более слабую версию или приобретать семантику, где это уместно, вместо последовательной согласованности по умолчанию, чтобы компилятор вообще не выдавал никаких инструкций барьера на x86. Он просто должен содержать операции в исходном порядке.


В слабо упорядоченной архитектуре, такой как ARM или PPC, или x86 с movnt, вам нужна инструкция барьера StoreStore между записью буфера и установкой флага, указывающего, что данные готовы. Кроме того, считывающему устройству необходима барьерная инструкция LoadLoad между проверкой флага и чтением буфера.

Не считая movnt, x86 уже имеет барьеры LoadLoad между каждой загрузкой и барьеры StoreStore между каждым хранилищем. (Также гарантируется заказ LoadStore). MFENCE - это все 4 вида барьеров, включая StoreLoad, который является единственным препятствием, которое x86 не выполняет по умолчанию. MFENCE следит за тем, чтобы загрузки не использовали старые предварительно выбранные значения до того, как другие потоки увидели ваши хранилища и, возможно, сделали свои собственные. (А также является препятствием для размещения заказов в магазинах NT и загрузки.)

Интересный факт: инструкции x86 с префиксом lock также являются барьером для полной памяти. Их можно использовать вместо MFENCE в старом 32-битном коде, который может работать на процессорах, не поддерживающих его. lock add [esp], 0 в противном случае не работает и выполняет цикл чтения / изменения / записи в памяти, которая, скорее всего, является горячей в кэше L1 и уже находится в состоянии M протокола когерентности MESI.

SFENCE - это барьер StoreStore. После хранилищ NT полезно создать семантику выпуска для следующего хранилища.

LFENCE почти всегда не имеет значения как барьер памяти, потому что единственная слабоупорядоченная нагрузка

LoadLoad и также барьер LoadStore. (loadNT / LFENCE / storeNT предотвращает то, что хранилище становится глобально видимым перед загрузкой. Я думаю, что это могло произойти на практике, если бы адрес загрузки был результатом длинной цепочки зависимостей или результатом другой загрузки, пропущенной в кеше.)


ERMSB строковые операции

Интересный факт № 2 (спасибо @EOF): магазины из ERMSB (Enhanced _17 _ / _ 18_ на IvyBridge и более поздних версиях) ) слабо упорядочены (но не с обходом кеша). ERMSB основывается на обычных операциях Fast-String (широкие запасы микрокодированной реализации rep stos/movsb, которая существует со времен PPro).

Intel документирует тот факт, что хранилища ERMSB «могут казаться работающими не по порядку», в разделе 7.3.9.3 своего Руководства для разработчиков программного обеспечения, том 1. Они также говорят

«Код, зависящий от порядка, должен писать в дискретную переменную семафора после любых строковых операций, чтобы все процессоры могли видеть правильно упорядоченные данные»

Они не упоминают о необходимости каких-либо барьерных инструкций между rep movsb и магазином до data_ready флажка.

Как я это читал, после rep stosb / rep movsb есть неявная SFENCE (по крайней мере, ограждение для строковых данных, возможно, не другие слабо упорядоченные хранилища NT на лету). В любом случае, формулировка подразумевает, что запись во флаг / семафор становится глобально видимой после всех операций записи с перемещением строки, поэтому SFENCE / LFENCE не требуется в коде, который заполняет буфер операцией быстрой строки. а затем записывает флаг или в код, который его читает.

(Упорядочивание LoadLoad всегда происходит, поэтому вы всегда видите данные в том порядке, в котором другие процессоры сделали их глобально видимыми. Т.е. использование слабо упорядоченных хранилищ для записи буфера не меняет того факта, что нагрузки в других потоках по-прежнему строго упорядочены.)

Резюме: используйте обычное хранилище для записи флага, указывающего, что буфер готов. Не давайте читателям, просто проверьте последний байт блока, записанного с помощью memset / memcpy.

Я также думаю, что хранилища ERMSB не позволяют другим хранилищам передавать их, поэтому вам все равно понадобится SFENCE, только если вы используете movNT. т.е. rep stosb в целом имеет семантику выпуска по отношению к. более ранние инструкции.

Есть бит MSR, который можно сбросить, чтобы отключить ERMSB в интересах новых серверов, которым необходимо запускать старые двоичные файлы, которые записывают флаг «данные готовы» как часть rep stosb или rep movsb или что-то в этом роде. (В этом случае я предполагаю, что вы получите старый микрокод с быстрой строкой, который может использовать эффективный протокол кеширования, но заставляет все хранилища отображаться для других ядер по порядку).

person Peter Cordes    schedule 21.09.2015
comment
Не только movnt имеет более слабый порядок памяти. Инструкции memcpy / strcpy (rep[ne] movs[b/w/d/q]) тоже. - person EOF; 22.09.2015
comment
@EOF: Спасибо, я этого не знал! Странно, что в руководстве insn ref это не упоминается, только в руководстве к Vol1. Я обновил свой ответ своей интерпретацией того, что говорят документы: существует неявный барьер StoreStore (для строковых данных) после rep movsb, поэтому вам просто нужно написать свой флаг готовности данных отдельно (а не как последние байты строки op ). - person Peter Cordes; 22.09.2015
comment
@EOF: Это не только movnt и rep[ne] movs[b/w/d/q]; но (потенциально) каждая инструкция, обращающаяся к памяти; учитывая, что модель упорядочения памяти можно ослабить, настроив либо таблицы PAT / page, либо MTRR для памяти, к которой осуществляется доступ, как объединение записи (а не обратной записи). - person Brendan; 28.09.2015
comment
@Brendan: Я предполагал контекст пользовательского процесса в обычной ОС, такой как Linux. Вы можете предположить, что все ваши страницы являются WB, если вы не выбрали специальную ОС для сопоставления любых других страниц. В большинстве случаев память WB работает намного лучше, чем любой другой тип. Тем не менее, интересный момент; правда, память WC слабо упорядочена. - person Peter Cordes; 28.09.2015
comment
@PeterCordes: предположения хороши, если они верны, но даже тогда приятно хотя бы знать, что есть случаи, когда это предположение неверно (например, драйверы устройств обращаются к областям ввода-вывода с отображением памяти, таким как память видеодисплея). - person Brendan; 28.08.2018
comment
@Brendan: Я думаю, что в моем ответе в его нынешней форме типы памяти упоминаются достаточно четко, чтобы не вводить в заблуждение. Но да, я думаю, что предположения по умолчанию других людей о контексте, когда вы используете asm, могут быть другими. Хорошая точка зрения. - person Peter Cordes; 28.08.2018