Как буфер хранения и буфер заполнения строк взаимодействуют друг с другом?

Я читал статью об атаках MDS RIDL: Rogue In-Flight Data Load. Они обсуждают, как Line Fill Buffer может вызвать утечку данных. Есть Об уязвимостях RIDL и воспроизведении нагрузок вопрос, в котором обсуждаются детали микроархитектуры эксплойта.

Одна вещь, которая мне непонятна после прочтения этого вопроса, - это зачем нам нужен буфер заполнения строки, если у нас уже есть буфер хранения.

Джон Маккалпин обсуждает, как связаны буфер хранилища и буфер заполнения строки в Как WC-буфер соотносится с LFB? на форумах Intel, но это не совсем проясняет мне ситуацию.

Для хранилищ в пространстве WB данные хранилища остаются в буфере хранилища до тех пор, пока хранилища не будут списаны. После вывода данные могут быть записаны в кэш данных L1 (если линия присутствует и имеет разрешение на запись), в противном случае LFB выделяется для промаха сохранения. LFB в конечном итоге получит «текущую» копию строки кэша, чтобы ее можно было установить в кэш данных L1, и данные хранилища можно было записать в кэш. Детали слияния, буферизации, упорядочивания и "кратчайшего пути" неясны ... Одна интерпретация, которая разумно согласуется с вышеизложенным, заключается в том, что LFB служат буферами размера строки кэша, в которых данные хранилища объединяются перед отправкой в кэш данных L1. По крайней мере, я думаю, что это имеет смысл, но я, наверное, что-то забываю ...

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

  1. Инструкции магазина планируются во внешнем интерфейсе.
  2. Выполняется в магазине.
  3. Запрос хранилища помещается в буфер хранилища (адрес и данные)
  4. Недействительный запрос чтения отправляется из буфера хранилища в систему кеширования.
  5. Если он пропускает кеш L1d, то запрос помещается в буфер заполнения строки.
  6. Буфер заполнения строки пересылает недействительный запрос чтения в L2.
  7. Некоторый кеш получает недействительное чтение и отправляет свою строку кеша
  8. Буфер хранилища применяет свое значение к входящей строке кэша
  9. Эм-м-м? Буфер заполнения строки помечает запись как недопустимую.

введите описание изображения здесь

Вопросов

  1. Зачем нам нужен буфер заполнения строки, если буфер хранилища уже существует для отслеживания исходящих запросов хранилища?
  2. Правильно ли порядок событий в моем описании?

person Daniel Näslund    schedule 09.04.2020    source источник
comment
LFB может отслеживать строку входящей кеш-памяти, а не только хранилище. LFB буферизует между L1d и L2 или вне ядра. Буфер хранилища буферизируется между выполнением и L1d (или вне ядра для хранилищ NT). Некоторые из описаний наличия данных в LFB, ожидающих слияния с результатом RFO, не имеют полностью смысла; мы не уверены, что процессоры действительно делают что-то подобное. то есть ментальная модель доктора Бандшайна (на момент написания этого конкретного поста) может там не соответствовать действительности. @ BeeOnRope, @ HadiBrais, и я обсудили, что имеет / не имеет для этого смысла, в предыдущих вопросах и ответах SO, IIRC   -  person Peter Cordes    schedule 10.04.2020
comment
@PeterCordes Поскольку каждому хранилищу предшествует RFO и поскольку данные с верхних уровней хранятся в LFB, возможно ли, что SB записывает в относительный LFB? Т.е. не использовать его в качестве временного буфера при выполнении RFO, а записывать в него после, когда RFO внесет в него данные. Теперь, если строка, на которую будет идти магазин, уже находится в состоянии EX, я не уверен, что LFB выделен. Это кажется пустой тратой времени. запись в строки данных напрямую, но, возможно, CAM кеша не позволяет частичную запись. В любом случае, у нас уже есть здесь канонический ответ о взаимодействии SB ‹-› LFB?   -  person Margaret Bloom    schedule 10.04.2020
comment
@MargaretBloom: IIRC, основные трудности с этой идеей фиксации из SB в LFB до того, как архитектурно разрешено (упорядочение памяти) для фиксации в L1d, заключается в том, что несколько хранилищ в одной строке теряют информацию о порядке памяти относительно друг друга (и что-нибудь еще). Мы должны поддерживать хранилища в порядке даже для кода, который чередует хранилища на две разные строки. В состоянии Exclusive или Modified нет причин ожидать, что LFB будет участвовать в фиксации от SB к L1d, и прежде чем мы достигнем этого состояния, он должен оставаться в SB для упорядочивания. IDK, если у нас есть канонические вопросы и ответы.   -  person Peter Cordes    schedule 10.04.2020
comment
@PeterCordes Зачем нам фиксировать хранилища в LFB прежде, чем это разрешено архитектурой? Я рассуждал о возможности SB писать в LFB после того, как RFO перенес строку в LFB и до сохранения ее в CAM кэша. Итак, все это происходит после того, как ядро ​​убедится, что хранилище разрешено с архитектурной точки зрения.   -  person Margaret Bloom    schedule 10.04.2020
comment
@MargaretBloom: О, теперь я понимаю, о чем вы говорили. Это звучит правдоподобно и будет законным, поскольку RFO завершено; нам просто нужно убедиться, что данные магазина отображаются при ответе другим ядрам. Мы уже хотим убедиться, что у нас есть шанс зафиксировать хотя бы одно хранилище, прежде чем снова отказаться от очереди. Так что да, возможно, мы сэкономим на портах записи в кеш, передав ожидающие хранилища из головы SB в LFB по мере поступления данных, возможно, пока кеш индексирует правильный набор / способ хранения LFB. Мы знаем, что NT-хранилища могут писать прямо в LFB, а не в кеш, они подключены   -  person Peter Cordes    schedule 10.04.2020


Ответы (2)


Зачем нам нужен буфер заполнения строки, если буфер хранилища уже существует для отслеживания выходящих запросов в хранилище?

Буфер хранилища используется для отслеживания хранилищ по порядку, как до, так и после выхода, но до фиксации в кэше L1 2. Буфер хранилища концептуально является полностью локальной вещью, которая на самом деле не заботится о промахах кеша. Буфер хранилища имеет дело с единицами отдельных хранилищ различных размеров. Чипы, такие как Intel Skylake, имеют буфер хранения более 50 записи.

Буферы заполнения строк в основном имеют дело с обеими загрузками и сохранениями, которые отсутствуют в кэше L1. По сути, это путь от кеша L1 к остальной подсистеме памяти и касается единиц размера строки кэша. Мы не ожидаем, что LFB будет задействован, если загрузка или сохранение попадают в кеш L1 1. У чипов Intel, таких как Skylake, намного меньше записей LFB, вероятно, от 10 до 12.

Правильно ли порядок событий в моем описании?

Почти. Вот как бы я изменил ваш список:

  1. Инструкции хранилища декодируются и разделяются на блоки данных хранилища и адреса хранилища, которые переименовываются, планируются и для них выделяется запись в буфере хранилища.
  2. The store uops execute in any order or simultaneously (the two sub-items can execute in either order depending mostly on which has its dependencies satisfied first).
    1. The store data uop writes the store data into the store buffer.
    2. Адрес хранилища uop выполняет преобразование V-P и записывает адрес (а) в буфер хранилища.
  3. В какой-то момент, когда все старые инструкции удаляются, инструкция сохранения удаляется. Это означает, что инструкция больше не является умозрительной, и результаты могут быть видны. На этом этапе хранилище остается в буфере хранилища и называется старшим хранилищем.
  4. Теперь хранилище ожидает, пока оно не окажется во главе буфера хранилища (это самое старое не зафиксированное хранилище), после чего оно зафиксируется (станет глобально наблюдаемым) в L1, если соответствующая строка кэша присутствует в L1 в Состояние MESIF Modified или Exclusive. (т.е. это ядро ​​владеет линией)
  5. Если строка отсутствует в требуемом состоянии (либо полностью отсутствует, т. Е. Отсутствует кэш, либо присутствует, но в неисключительном состоянии), разрешение на изменение строки и данных строки (иногда) должно быть получено из Подсистема памяти: выделяет LFB для всей строки, если она еще не выделена. Это так называемый запрос на владение (RFO), что означает, что иерархия памяти должна вернуть строку в исключительном состоянии, подходящем для модификации, в отличие от общего состояния, подходящего только для чтения (это делает недействительными копии строки, присутствующие в любых других частных кэшах).

RFO для преобразования Shared в Exclusive все еще должен ждать ответа, чтобы убедиться, что все другие кеши сделали свои копии недействительными. В ответ на такое признание недействительности не нужно включать копию данных, потому что в этом кэше она уже есть. Его все еще можно назвать RFO; важная часть - получение права собственности до изменения линии. 6. В сценарии пропуска LFB в конечном итоге возвращается с полным содержимым строки, которое фиксируется на L1, и теперь ожидающее хранилище может зафиксировать 3.

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

В качестве одного примера, в приведенном выше порядке строки промахов магазина не выбираются до тех пор, пока магазин не достигнет заголовка очереди магазина. В действительности подсистема хранилища может реализовать тип предварительной выборки RFO, при котором очередь хранилища проверяется на предмет предстоящих хранилищ, и если строки отсутствуют в L1, запрос запускается раньше (фактическая видимая фиксация до L1 все еще должно происходить по порядку, на x86 или, по крайней мере, как если бы по порядку).

Таким образом, использование запроса и LFB может произойти уже после завершения шага 3 (если предварительная выборка RFO применяется только после закрытия магазина) или, возможно, даже после завершения 2.2, если младшие хранилища подлежат предварительной выборке.

В качестве другого примера шаг 6 описывает строку, возвращающуюся из иерархии памяти и фиксирующуюся в L1, затем фиксируется хранилище. Возможно, что ожидающее хранилище фактически объединяется с возвращаемыми данными, а затем записывается в L1. Также возможно, что хранилище может покинуть буфер хранилища даже в случае промаха и просто ждать в LFB, освобождая некоторые записи буфера хранилища.


1 В случае хранилищ, попавших в кэш L1, есть предположение, что LFB действительно задействованы: каждое хранилище фактически входит в объединяющий буфер (который может просто быть LFB) перед фиксацией в кеше, так что ряд хранилищ, нацеленных на одну и ту же строку кеша, объединяются в кеш и нуждаются в доступе к L1 только один раз. Это не доказано, но в любом случае это не является частью основного использования LFB (что более очевидно из того факта, что мы даже не можем точно сказать, происходит это или нет).

2 Буферы, в которых хранятся до и после списания, могут быть двумя совершенно разными структурами, с разными размерами и поведением, но здесь мы будем называть их одной структурой.

3 Описанные сценарии включают хранилище, которое пропускает ожидание в начале буфера хранилища, пока связанная строка не вернется. Альтернативный сценарий состоит в том, что данные хранилища записываются в LFB, используемый для запроса, и запись буфера хранилища может быть освобождена. Это потенциально позволяет обрабатывать некоторые последующие хранилища, пока происходит промах, в соответствии со строгими требованиями к порядку хранения x86. Это могло увеличить магазин MLP.

person BeeOnRope    schedule 10.04.2020
comment
Вы сказали, что шаг 4 (отправка недействительного запроса) происходит позже, когда хранилище будет готово к фиксации. Концепции выхода на пенсию / фиксации для меня новы. Правильная ли это последовательность событий: 1. ИУП выполняется в исполнительном блоке хранилища 2. Он помещается в буфер хранилища 3. ИУП хранилища находится в буфере переупорядочения модулей удаления (ROB) до тех пор, пока не станет известно, что это не так. -speculative 4. Буфер хранилища отправляет недействительный запрос чтения (это может занять некоторое время, но поскольку буфер хранилища отслеживает запрос, хранилище не должно ждать) ... продолжение следует .. - person Daniel Näslund; 10.04.2020
comment
Шаги 5-7 в моем вопросе происходят. Затем буфер хранилища применяет свое значение и, таким образом, фиксируется. - person Daniel Näslund; 10.04.2020
comment
@ DanielNäslund - Я создал свой собственный список, посмотрите, есть ли в нем смысл. WRT к вашему вопросу, я считаю, что запись буфера хранилища фактически выделяется при переименовании, что происходит даже до выполнения (мопы входят в планировщик при переименовании). Запись буфера в этот момент в основном пуста, а затем отдельные мопы адреса и данных заполняют их в запись буфера при выполнении. После вывода на пенсию можно думать о буфере хранилища, работающем по порядку: хранилища фиксируются на L1 по одному в том порядке, в котором они появляются в источнике (это требование сильной памяти ... - person BeeOnRope; 12.04.2020
comment
заказ на x86, где запрещено переупорядочивать хранилища в памяти WB). Однако возможна оптимизация этой простой модели «по одному за раз» в том смысле, что система магазинов может рассчитывать на отложенные магазины и начать получать эти строки раньше. Таким образом, промах не обязательно обрабатывается в точно указанный момент, а скорее в диапазоне времен, который также может зависеть от конкретного процессора, эвристики / предикторов, проверяющих, помогает ли предварительная выборка RFO на практике, и т. Д. - person BeeOnRope; 12.04.2020
comment
Я добавил немного к записи 5 о RFO для линий, которые присутствовали, но совместно использовались (не принадлежали исключительно) - person Peter Cordes; 12.04.2020
comment
Спасибо @PeterCordes, забыл об этом сценарии, а теперь добавил еще немного. - person BeeOnRope; 12.04.2020
comment
Знаем ли мы, что для разделенного хранилища строк кэша по-прежнему требуется только одна запись SB, для фиксации которой требуются дополнительные циклы? Как вы говорите, он полностью локален и на самом деле не заботится о промахах кеша L1d, поэтому это кажется возможным. Я предполагаю, что это можно проверить с помощью эксперимента, в котором заполнение SB предотвращало выполнение OoO некоторых цепочек депо до / после блока хранилищ. Если это так, мне интересно, можем ли мы протестировать объединение в SB, используя разделенные хранилища, чтобы получить работу в SB быстрее, чем он может передать горячие строки L1d, смешивая разделенные хранилища с парой хранилищ двойного слова в половину qword. - person Peter Cordes; 12.04.2020
comment
@PeterCordes - я бы предположил, что требуется только одна запись SB: поскольку они выделяются при переименовании, прежде чем вы узнаете, что она разделена, и ей просто нужно удерживать данные и адрес, а затем при фиксации выполняется разделение? Было бы очень легко протестировать на основе модификации теста 33 robsize (просто измените магазины на расколоть). - person BeeOnRope; 13.04.2020
comment
@BeeOnRope: да, распределение SB было еще одной частью моих мыслей, которые я забыл напечатать. Я задавался вопросом, могут ли хранилища с разделением страниц быть настолько дорогими из-за, возможно, необходимости выделять другую запись SB, или просто из-за того, что это за механизм; может быть, в каждой записи есть место для двух физических адресов в случае разделения страницы? - person Peter Cordes; 13.04.2020
comment
@PeterCordes - хорошее замечание о двух физических адресах. Позвольте мне изменить тест 33 ... - person BeeOnRope; 13.04.2020

Когда uops достигают распределителя, в схеме PRF + Retirement RAT (SnB и далее), распределитель обращается к RAT внешнего интерфейса (F-RAT), когда это необходимо для переименования записей ROB (т. Е. Когда запись в архитектурный регистр ( например, rax) выполняется) он назначается каждому uop в конце указателя ROB. RAT хранит список свободных и используемых регистров физического назначения (pdsts) в PRF. RAT возвращает свободные номера физических регистров, которые должны использоваться, а затем ROB помещает их в соответствующие записи (в схеме RRF распределитель предоставил RAT используемые pdsts; RAT не смог выбрать, потому что pdsts по сути, находились на хвостовом указателе ROB). RAT также обновляет каждый указатель архитектурного регистра с помощью назначенного ему регистра, то есть теперь он указывает на регистр, который содержит самые последние данные записи в программном порядке. В то же время ROB размещает запись на Станции бронирования (RS). В случае магазина он разместит uop адреса магазина и uop данных магазина в RS. Распределитель также выделяет записи SDB (буфер данных хранилища) / SAB (буфер адреса хранилища) и выделяет их только тогда, когда доступны все необходимые записи в ROB / RS / RAT / SDB / SAB.

Как только эти мопы выделяются в RS, RS считывает физические регистры для своих исходных операндов и сохраняет их в поле данных и в то же время проверяет шины обратной записи EU на предмет этих исходных PR (физических регистров), связанных записей ROB и данные обратной записи по мере их записи обратно в ROB. Затем RS планирует отправку этих мопов на порты store-address и store-data, когда они получат все свои завершенные исходные данные.

Затем отправляются пакеты uop - адрес хранилища uop переходит в AGU, а AGU генерирует адрес, преобразует его в линейный адрес и затем записывает результат в SAB. Я не думаю, что хранилище вообще требует PR в схеме PRF + R-RAT (это означает, что на этом этапе не требуется обратная запись в ROB), но в схеме RRF записи ROB были вынуждены использовать свои встроенный PR и все остальное (записи ROB / RS / MOB) были идентифицированы их номерами PR. Одним из преимуществ схемы PRF + R-RAT является то, что ROB и, следовательно, максимальное количество мопов в полете могут быть расширены без необходимости увеличения количества PR (поскольку будут инструкции, которые не требуют никаких), и все адресуется номерами записей ROB в случае, если записи не имеют идентифицирующих PR.

Данные магазина проходят напрямую через конвертер магазина (STC) в SDB. Как только они отправлены, они могут быть освобождены для повторного использования другими мопами. Это предотвращает ограничение гораздо большего ROB размером RS.

Затем адрес отправляется в dTLB, и он сохраняет вывод физического тега из dTLB в PAB кэша L1d.

Распределитель уже выделил SBID и соответствующие записи в SAB / SDB для этой записи ROB (мопы STA + STD микроплиты в одну запись), которые буферизуют результаты диспетчерского выполнения в AGU / TLB от RS. Магазины находятся в SAB / SDB с соответствующей записью с тем же номером записи. (SBID), который связывает их вместе, до тех пор, пока MOB не будет проинформирован отделением вывода о том, какие магазины готовы к выводу из эксплуатации, т.е. они больше не являются спекулятивными, и он не будет проинформирован о совпадении CAM указателя извлечения записи ROB, указывающего на индекс ROB / ID, который содержится в записи SAB / SDB (в uarch, который может выводить из строя 3 мопа за цикл, есть 3 указателя вывода, которые указывают на 3 самые старые неизвлекаемые инструкции в ROB, и только битовые шаблоны готовности ROB 0,0 , 1 0,1,1 и 1,1,1 разрешают поиск совпадений CAM-указателей для продолжения). На этом этапе они могут быть выведены из эксплуатации в ROB (известном как «списать / завершить локально») и стать старшими хранилищами и помечены старшим битом (бит Ae для STA, бит De для STD) и медленно отправляются в L1d. кеш, пока данные в SAB / SDB / PAB действительны.

Кэш L1d использует линейный индекс в SAB для декодирования набора в массиве тегов, который будет содержать данные с использованием линейного индекса, и в следующем цикле использует соответствующую запись PAB с тем же значением индекса, что и SBID, для сравнения физического тег с тегами в наборе. Вся цель PAB состоит в том, чтобы разрешить ранний поиск TLB для магазинов, чтобы скрыть накладные расходы на промах dTLB, пока они не делают ничего другого, ожидая, чтобы стать старшим, и разрешить спекулятивные обходы страниц, пока магазины все еще фактически спекулятивны. Если хранилище является сразу старшим, то этот ранний поиск TLB, вероятно, не происходит, и он просто отправляется, и именно тогда кеш L1d декодирует набор массивов тегов и параллельно ищет dTLB, а PAB обходится. Однако помните, что он не может выйти из ROB до тех пор, пока не будет выполнена трансляция TLB, потому что может быть код исключения PMH (ошибка страницы или чтение битов доступа / грязных битов необходимо установить при выполнении обхода страницы) или исключение код, когда TLB необходимо записать через биты доступа / грязные биты, которые он устанавливает в записи TLB. Вполне возможно, что поиск TLB для хранилища всегда происходит на этом этапе и не выполняет его параллельно с установленным декодированием (в отличие от загрузок). Хранилище становится старшим, когда PA в PAB становится действительным (действительный бит установлен в SAB), и он готов к списанию в ROB.

Затем он проверяет состояние линии. Если это общая линия, физический адрес отправляется в домен согласованности в RFO (всегда RFO для записи), и когда он владеет линией, он записывает данные в кэш. Если строка отсутствует, то для этой строки кэша выделяется LFB, и данные хранилища хранятся в нем, и запрос отправляется в L2, который затем проверяет состояние строки в L2 и инициирует чтение или RFO на кольцевой интерфейс IDI.

Хранилище становится глобально видимым, когда RFO завершается, и бит в LFB указывает, что у него есть разрешение на запись строки, что означает, что LFB будет последовательно записан обратно при следующем аннулировании или выселении отслеживания (или в случае попадания, когда данные записываются в строку). Он не считается глобально видимым, если он просто записывается в LFB до того, как происходит выборка строки в случае промаха (в отличие от старших нагрузок, которые удаляются при попадании или когда LFB отключается. выделены кешем L1d), потому что могут быть другие RFO, инициированные другими ядрами, которые могут достичь контроллера слайса LLC до запроса от текущего ядра, что было бы проблемой, если бы SFENCE на текущем ядре был удален на основе этой версии «глобально видимого» вывода из эксплуатации - по крайней мере, это обеспечивает гарантию синхронизации для межпроцессорных прерываний. Глобально видимый - это тот самый момент, когда эти сохраненные данные будут считаны другим ядром, если нагрузка произойдет на другом ядре, а не момент, когда она будет через небольшой промежуток времени, когда до этого старое значение все еще будет считываться другими ядрами. Сохранение завершается кешем L1d после выделения LFB (или когда они записываются в строку в случае попадания) и удаляются из SAB / SDB. Когда все предыдущие хранилища удалены из SAB / SDB, именно тогда store_address_fence (не store_address_mfence) и связанный с ним store_data_fence могут быть отправлены в L1d. Для LFENCE более практично сериализовать поток инструкций ROB, тогда как _7 _ / _ 8_ этого не делать, потому что это потенциально может вызвать очень долгую задержку в ROB для глобальной видимости и не является необходимым, в отличие от старших нагрузок, которые удаляются мгновенно, поэтому имеет смысл, почему LFENCE был выбран забором для одновременной сериализации потока инструкций. SFENCE/MFENCE не удаляются, пока все выделенные LFB не станут глобально видимыми.

Буфер заполнения строки может находиться в одном из трех режимов: чтение, запись или объединение записи. Я думаю, что цель буфера заполнения строки записи состоит в том, чтобы объединить несколько хранилищ с данными одной строки в LFB, а затем, когда строка прибывает, заполнить недействительные биты данными, полученными из L2. Возможно, на этом этапе он считается завершенным, и поэтому записи выполняются в большом количестве и на цикл раньше, а не дожидаются их записи в строку. При условии, что теперь гарантируется запись обратно в кэш в ответ на RFO другого ядра. LFB, вероятно, останется выделенным до тех пор, пока его не нужно будет освободить, что позволит немного быстрее удовлетворить последующие операции чтения и записи в ту же строку. Буфер строки чтения может обслуживать пропуски чтения на несколько циклов быстрее, потому что он мгновенно доступен в буфере заполнения строки, но требует больше времени, чтобы записать его в строку кэша, а затем прочитать из нее. Буфер объединения записи выделяется, когда память относится к типу USWC, и позволяет выполнять запись немедленно и сбрасывать ее на устройство MMIO сразу, вместо того, чтобы иметь несколько транзакций Core- ›PCIe и иметь несколько транзакций PCIe. Буфер WC также допускает спекулятивное чтение из буфера. Обычно спекулятивные чтения не допускаются в памяти UC, потому что чтение может изменить состояние устройства MMIO, но также чтение / запись занимает так много времени, что к тому времени, когда оно завершится, оно больше не будет спекулятивным и поэтому, возможно, не стоит дополнительных движение? LFB, скорее всего, является VIPT (VIPT / PIPT такие же на intel, а V - линейный адрес на intel); Я предполагаю, что у него может быть физический и виртуальный теги, чтобы исключить дальнейшие поиски TLB, но ему придется что-то согласовывать, когда физическая страница мигрирует на новый физический адрес.

person Lewis Kelsey    schedule 26.01.2021
comment
LFENCE также должен упорядочить любые потенциально слабо упорядоченные нагрузки (например, SSE4.1 movntdqa), и один из простых способов сделать это - убедиться, что все предыдущие нагрузки удалены. (Потому что на x86 это означает полное завершение, а не ожидание значения.) Кажется возможным, что Intel рассматривала идею ослабления модели памяти x86, когда они представили LFENCE или что-то в этом роде. - person Peter Cordes; 28.01.2021
comment
@PeterCordes Я думал, только магазины NT слабо заказаны. Я напишу ответ по имеющейся у меня модели загрузочного оборудования в какой-то момент, если найду соответствующий вопрос. - person Lewis Kelsey; 29.01.2021
comment
movntdqa загрузки из памяти WC слабо упорядочены. Но в отличие от хранилищ NT, movntdqa не отменяет атрибут типа памяти. Некоторое время назад я писал Невременные нагрузки и аппаратный модуль предварительной выборки, работают ли они вместе?; У меня есть наполовину законченное обновление, в котором указывается, что для возможной работы потребуются программы предварительной выборки HW с поддержкой NT, и существует конфликт между действительным обходом кеша для нагрузок и поддержанием согласованности (или необходимыми дополнительными HW). Также обратите внимание, что обычные хранилища в памяти WC также слабо упорядочены, они точно такие же, как хранилища NT. - person Peter Cordes; 29.01.2021
comment
@PeterCordes О, да, теперь я вспомнил, я думаю, что упомянул об этом в ответе, который я написал некоторое время назад о записи, объединяющей буферы, и было что-то, связанное с этим, что я не решил, но, возможно, смогу сейчас. Это также обсуждалось здесь: stackoverflow.com/a/53199688/7194773 - person Lewis Kelsey; 29.01.2021