Процессор останавливается во время операции когерентности кэша - PullRequest
3 голосов
/ 02 апреля 2019

Предположим, что переменная a = 0

Processor1: a = 1
Processor2: print(a)

Процессор1 сначала выполняет свою инструкцию, а затем в следующем цикле процессор2 читает переменную, чтобы распечатать ее.Так что:

  1. процессор 2 остановится до завершения операции когерентности кэша и напечатает 1

    P1:   |--a=1--|---cache--coherence---|----------------
    P2:   ------|stalls due to coherence-|--print(a=1)---|
    time: ----------------------------------------------->
    
  2. процессор 2 будет работать до операции когерентности кэшазавершает и будет иметь устаревший вид памяти до тех пор.Таким образом, он выведет 0?

    P1:   |--a=1--|---cache--coherence---|
    P2:   ----------|---print(a=0)---|----
    time: ------------------------------->
    

    Другими словами, может ли процессор иметь устаревшее представление памяти до тех пор, пока операции когерентности кэша не будут завершены?

Ответы [ 2 ]

5 голосов
/ 02 апреля 2019

Все современные ISA используют (вариант) MESI для когерентности кэша.Это обеспечивает согласованность во все времена общего представления памяти (через кэш), которое есть у всех процессоров.

См., Например, Можно ли принудительно установить когерентность кэша на многоядерном процессоре x86? Это распространенное явлениезаблуждение, что хранилища идут в кэш, в то время как другие ядра все еще имеют старые копии строки кэша, и тогда должна произойти «когерентность кэша».

Но это не так: чтобы изменить строку кэша, ЦПУ необходимоиметь исключительное владение линией (измененное или исключительное состояние MESI).Это возможно только после получения ответов на чтение для владельца, которое делает недействительными все остальные копии строки кэша, если ранее она находилась в состоянии общего или недействительного.См. Будут ли две атомные записи в разные места в разных потоках всегда рассматриваться в одном и том же порядке другими потоками? * Например, 1012 *.


Однако модели памяти допускают локальное переупорядочениемагазинов и грузов .Последовательная согласованность будет слишком медленной, поэтому процессоры всегда допускают как минимум переупорядочение StoreLoad.См. Также Безопасен ли mov + mfence для NUMA? для получения подробной информации о модели памяти TSO (общий порядок хранения), используемой в x86.Многие другие ISA используют еще более слабую модель.

Для несинхронизированного считывателя в этом случае есть три возможности, если оба работают на отдельных ядрах

  • load(a) происходит на ядре #2 до того, как строка кэша будет признана недействительной, поэтому она считывает старое значение и, таким образом, эффективно происходит до сохранения a=1 в глобальном порядке. Загрузка может ударить в кэш-памяти L1d .
  • load(a) происходит после того, как ядро ​​# 1 зафиксировало хранилище в своем кэш-памяти L1d и еще не отозвало.Запрос на чтение в Core # 2 запускает Core # 2 для обратной записи в совместно используемый общий уровень кэша (например, L3) и переводит строку в состояние Shared. Загрузка определенно будет отсутствовать в L1d .
  • load(a) происходит после обратной записи в память или, по крайней мере, L3 уже произошла, поэтому ей не нужно ждать ядра # 1отписаться Загрузка будет отсутствовать в L1d , если аппаратная предварительная выборка не вернула его по какой-либо причине.Но обычно это происходит только как часть последовательного доступа (например, к массиву).

Так что да, загрузка остановится, если другое ядро ​​уже передало ее в кеш, прежде чем это ядро ​​попытается

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

Здесь не имеет значения, потому что у вас есть производитель только для записи и только для чтенияпотребитель.Ядро производителя не ждет, пока его магазин станет глобально видимым, прежде чем продолжить, и он может сразу увидеть свой собственный магазин, прежде чем он станет глобально видимым. имеет значение , когда каждый поток просматривает хранилища, созданные другим потоком;тогда вам нужны барьеры или последовательно согласованные атомарные операции (которые компиляторы реализуют с барьерами). См. https://preshing.com/20120515/memory-reordering-caught-in-the-act

См. Также Может ли num ++ быть атомарным для 'int num'? о том, как атомарный RMW работает с MESI, поучительно для понимания концепции.(например, что атомарный RMW может работать, заставляя ядро ​​зависать в строке кэша в состоянии Modified и задерживать ответ на RFO или запросы на его совместное использование до тех пор, пока часть записи RMW не будет зафиксирована.)

3 голосов
/ 02 апреля 2019

Доступ на чтение и запись к a в этом примере является одновременным и может завершаться в любом порядке.Это зависит от того, какой процессор получает доступ к линии первым.Когерентность кэша только гарантирует, что все процессоры в одном домене когерентности согласуются со значениями, хранящимися во всех строках кэша.Таким образом, конечный результат не может состоять в том, что существует две копии a, одна со значением 0, а другая 1. 1. 1003 *

Если вы хотите убедиться, что процессор2 видит значение, записанное процессором1, тоВы должны использовать механизм синхронизации.Простой, но неэффективный способ достижения этого:

Processor1: 
a = 1
rel = 1

Processor2: 
while(rel != 1){ }
print(a)

Это работает, если выполняются следующие свойства:

  • Хранилища завершаются в порядке как на уровне компилятора, так и на уровнеуровень ISA.
  • Загрузка выполняется по порядку как на уровне компилятора, так и на уровне ISA.

Примером ISA, который удовлетворяет этим свойствам, является x86-64, при условиичто rel не больше 8 байт и выровнено естественным образом, и все переменные не выделены из области памяти типа памяти WC.


Относительно вашего обновления вопроса.Если процессор 1 получил владение строкой до того, как он будет считан процессором 2, процессор 2 может остановиться, пока процессор 1 не завершит свою операцию записи и не получит обновленную строку.Processor1 может принять решение об отказе от владения линией, прежде чем он выполнит запись в нее, если обнаружит запрос на чтение в строке от другого процессора.Но что бы ни случилось, два доступа завершатся в некотором порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...