Барьер памяти действует как маркер и как инструкция?

Я читал разные вещи о том, как работает барьер памяти.

Например, ответ пользователя Johan на этот вопрос говорит, что барьер памяти - это инструкция, которую выполняет CPU.

В то время как комментарий пользователя Peter Cordes в этом вопросе говорит о том, как процессор переупорядочивает инструкции:

Он читает быстрее, чем может выполнить, поэтому он может видеть окно предстоящих инструкций. Подробности смотрите в некоторых ссылках в вики-теге x86, таких как pdf-файл Agner Fog's microarch, а также в статье Дэвида Кантера о разработке Intel Haswell. Конечно, если вы просто погуглили "не по порядку", вы найдете статью в Википедии, которую вы должны прочитать.

Таким образом, я предполагаю, исходя из приведенного выше комментария, что если между инструкциями существует барьер памяти, ЦП увидит этот барьер памяти, который заставляет ЦП не переупорядочивать инструкции, поэтому это означает, что барьер памяти является "маркером" для процессора, чтобы увидеть, а не выполнить.


Теперь я предполагаю, что барьер памяти действует как маркер и как инструкция для процессора для выполнения.

Для маркерной части ЦП видит барьер памяти между инструкциями, что заставляет ЦП не переупорядочивать инструкции.

Что касается инструкционной части, ЦП будет выполнять инструкцию по барьеру памяти, что заставляет ЦП выполнять такие вещи, как очистка буфера хранения, а затем ЦП будет продолжать выполнять инструкции после барьера памяти.

Я прав?

1 ответ

Нет, mfence не сериализуется в потоке команд, и lfence (который) не очищает буфер хранилища.

(На практике на Skylake, mfence блокирует неупорядоченное выполнение последующих инструкций ALU, а не только загружает. ( Доказательство: подробности эксперимента внизу этого ответа). Таким образом, он реализован как барьер для исполнения, хотя на бумаге он не обязательно должен быть. Но lock xchg нет, и это также полный барьер.)

Я бы посоветовал прочитать статью Джеффа Прешинга " Барьеры памяти", как операции управления исходным кодом, чтобы лучше понять, что нужно делать с барьерами памяти, а что нет. Они не должны (должны) блокировать выполнение не по порядку в целом.


Барьер памяти ограничивает порядок, в котором операции с памятью могут стать глобально видимыми, а не (обязательно) порядок, в котором выполняются инструкции. Прочитайте обновленный ответ @BeeOnRope на ваш предыдущий вопрос еще раз: Есть ли инструкции по переупорядочению процессора x86? чтобы узнать больше о том, как переупорядочение памяти может происходить без OoO exec, и как OoO exec может происходить без переупорядочения памяти.

Остановка конвейера и очистка буферов - это один (низкоэффективный) способ реализации барьеров, используемых на некоторых микросхемах ARM, но более производительные ЦП с большим отслеживанием упорядочения памяти могут иметь более дешевые барьеры памяти, которые ограничивают только порядок операций с памятью, не все инструкции. А для операций с памятью они контролируют порядок доступа к кэшу L1d (на другом конце буфера хранилища), а не порядок, в котором хранятся данные, записываемые в буфер хранилища.

x86 уже нуждается в большом количестве отслеживания порядка памяти для обычных загрузок / хранилищ для высокой производительности, сохраняя при этом свою строго упорядоченную модель памяти, в которой только переупорядочивание StoreLoad может быть видимым для наблюдателей вне ядра (то есть хранилища могут быть буферизированы до последующих загрузок), (Руководство по оптимизации Intel использует термин Memory Order Buffer, или MOB, вместо буфера хранилища, потому что он также должен отслеживать порядок загрузки. Он должен очистить машину упорядочивания памяти, если окажется, что спекулятивная нагрузка тоже приняла данные на ранних этапах.) Современные процессоры x86 сохраняют иллюзию уважения к модели памяти, фактически выполняя загрузку и агрессивно сохраняя неупорядоченные данные.

mfence может выполнить свою работу, просто записав маркер в буфер порядка памяти, не будучи барьером для неупорядоченного выполнения последующих инструкций ALU. Этот маркер должен по крайней мере препятствовать выполнению последующих загрузок до mfence маркер достигает конца буфера хранилища. (А также упорядочение хранилищ NT и операций со слабо упорядоченной памятью WC).

(Но, опять же, более простое поведение является допустимым вариантом реализации, например, не позволяя ни одному хранилищу после mfence записывать данные в буфер хранилища до тех пор, пока все более ранние загрузки не прекратятся и более ранние хранилища не передадут в кэш L1d. т.е. полностью опустошить буфер MOB / store. Я не знаю точно, что делают нынешние процессоры Intel или AMD.)


На Skylake конкретно мои тесты показывают mfence это 4 мопа для внешнего интерфейса (слитый домен) и 2 мопа, которые фактически выполняются на портах исполнения (один для порта 2/3 (загрузка / адрес хранения) и один для порта 4 (хранение данных)). Предположительно это особый тип UOP, который записывает маркер в буфер порядка памяти. 2 мопа, которые не нуждаются в исполнительном модуле, могут быть похожи на lfence, Я не уверен, блокируют ли они интерфейсную часть даже от более поздней загрузки, но, надеюсь, не потому, что это остановит выполнение последующих независимых операций ALU.


lfence интересный случай: помимо барьера LoadLoad + LoadStore (даже для слабо упорядоченных нагрузок; обычные загрузки / хранилища уже заказаны), lfence также является слабым барьером исполнения (обратите внимание, что mfence не просто lfence). Он не может быть выполнен до тех пор, пока все более ранние инструкции не будут "выполнены локально". Предположительно, это означает, что "вышел в отставку" из ядра, вышедшего из строя.

Но магазин не может зафиксировать кэш L1d до тех пор, пока он все равно не выйдет из системы (то есть после того, как он, как известно, будет не спекулятивным), поэтому ожидание выхода магазинов из ROB (буфер перезаписи для мопов) - это не то же самое, что ожидание для буфера магазина, чтобы очистить. См. Почему (или нет?) SFENCE + LFENCE эквивалентно MFENCE?,

Так что да, конвейер процессора должен "заметить" lfence до его выполнения, предположительно на этапе выпуска / переименования. Я понимаю, что lfence не может выдать, пока ROB не опустеет. (На процессорах Intel, lfence По словам Агнера Фога, для фронтэнда это 2 мопа, но ни одному из них не нужны исполнительные блоки. http://agner.org/optimize/.)

lfence еще дешевле на AMD Bulldozer-family: 1 мегапиксель с пропускной способностью 4 на тактовую частоту. IIRC, он не частично сериализуется на этих процессорах, поэтому вы можете использовать только lfence; rdtsc прекратить rdtsc от выборки часов рано на процессорах Intel.


Для полной сериализации инструкций, таких как cpuid или же iret, он также будет ждать, пока буфер хранилища не будет исчерпан. ( Они являются полными барьерами памяти, такими же сильными, как mfence). Или что-то типа того; они множественные мопы, так что, возможно, только последний выполняет сериализацию, я не уверен, с какой стороны барьера на самом деле работает cpuid происходит (или если он не может перекрываться с более ранними или более поздними инструкциями). В любом случае, сам конвейер должен замечать сериализованные инструкции, но полный эффект барьера памяти может быть от мопов, которые делают то, что mfence делает.


Бонусное чтение:

На AMD Bulldozer-family, sfence так же дорого, как mfence и может быть столь же сильным барьером. (Документы x86 устанавливают минимум для того, насколько силен каждый тип барьера; они не мешают им быть сильнее, потому что это не проблема правильности). Ризен отличается: sfence имеет пропускную способность один на 20c, в то время как mfence 1 на 70c.

sfence это очень дешево для Intel (моп для port2/port3 и моп для port4), и просто заказывает NT-магазины относительно. обычные хранилища, без очистки буфера хранилища или сериализации. Может выполняться по одному на 6 циклов.

sfence не истощает буфер хранилища до выхода на пенсию. Он не станет глобально видимым сам по себе, пока все предыдущие хранилища не станут глобально видимыми первыми, но это отделено от конвейера выполнения буфером хранилища. Буфер хранилища всегда пытается опустошить себя (т.е. зафиксировать хранилища в L1d), поэтому sfence не нужно делать ничего особенного, за исключением того, что в MOB ставится особая отметка, которая не позволяет магазинам NT переупорядочивать ее, в отличие от отметок, которые ставят обычные магазины, которые только заказывают. обычные магазины и более поздние грузы.


Он читает быстрее, чем может выполнить, поэтому он может видеть окно предстоящих инструкций.

Посмотрите этот ответ, который я написал, который является более подробной версией моего комментария. В нем рассматриваются некоторые основы того, как современный процессор x86 находит и использует параллелизм на уровне команд, рассматривая еще не выполненные инструкции.

В коде с высоким ILP недавние процессоры Intel могут на самом деле достаточно узким местом во внешнем интерфейсе; Внутренний сервер имеет так много исполнительных блоков, что он редко является узким местом, если нет зависимости данных или ошибок в кэше, или если вы используете много отдельных инструкций, которые могут выполняться только на ограниченных портах. (например, вектор тасует). Но всякий раз, когда бэкэнд не поспевает за фронтэндом, окно не по порядку начинает заполняться инструкциями по нахождению параллелизма.

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