Являются ли операции кэширования атомарными?

Я изучаю кэш-память процессора, и теперь у меня все еще непонимание протокола согласованности кэша (MESI). Представьте, что у нас 2 ядра имеют строку кэша в общем состоянии. И один из них выполняет чтение, другой выполняет запись:

 ;mem is cached in Shared state
 Thread 1 (core 1)          Thread 2 (core 2)
  mov rax, [mem]            mov [mem], dword 1

Может ли ядро ​​1 наблюдать какое-то промежуточное состояние. Я имею в виду что-то вроде следующего:

  1. Core 2 отмечает строку кэша в L1D как изменено и пишет изменения в него.
  2. Строка кэша в core 1"s L1D кеш все еще в Shared состояние, поэтому чтение происходит, чтобы прочитать устаревшее значение.
  3. После того, как чтение устаревшего значения уже произошло, строка в core 1"s L1D кеш помечен как недействительный.

Возможен ли такой сценарий в реализации Intel MESI/MESIF?

2 ответа

Решение

Строка кэша в кэш-памяти L1D ядра 1 все еще находится в состоянии общего доступа.

Это та часть сценария, которая нарушает МЭСИ. Хранилище не может зафиксировать, пока RFO, отправленный ядром 2, не завершится, поэтому ядро ​​1 имеет строку в неверном состоянии.

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

Хранилища не становятся глобально видимыми до тех пор, пока они не будут выполнены локально (они должны удалиться, а затем очередь хранилища сможет зафиксировать их в L1D), а модель памяти x86 позволяет переупорядочивать StoreLoad, поэтому хранилища могут быть отложены (скрыты в частном хранилище). очереди) до тех пор, пока последующие загрузки ядра 2 не станут видны глобально. (См. Раздел " Барьеры памяти Джеффа Пришинга", как операции управления исходным кодом, для получения дополнительной информации о переупорядочении памяти и о том, что означает переупорядочение StoreLoad).


В MESI (и во всех вариантах, таких как MESIF или MOESI), если один кэш имеет строку в состоянии E или M, никакие другие кэши не могут иметь копию этой строки. Таблица состояний в статье MESI wikipedia проясняет это: если один кэш имеет состояние E или M, у всех остальных - Invalid.

Два кэша никогда не смогут иметь действительные копии строки с разными данными. Именно это означает, что кэши должны быть связными, и предотвращение этого - вот и весь смысл протокола MESI.

Если ядро ​​хочет изменить строку кэша, оно получает исключительное владение строкой, поэтому никакие другие ядра не могут наблюдать устаревшие значения. Это должно произойти до того, как магазин сможет перейти в L1D. Очереди хранилища существуют, чтобы скрыть задержку Read-For-Ownership (среди прочего), но данные в очереди хранилища еще не переданы в L1D. (Связано: что происходит, когда разные ядра ЦП записывают на один и тот же адрес ОЗУ без синхронизации? Больше о очереди хранилища).


И кстати, давайте предположим, что [mem] выравнивается естественным образом, поэтому загрузка / сохранение в нем являются атомарными (что гарантируется архитектурой x86). Почему целочисленное присваивание для естественно выровненной переменной атомарно в x86?,


Многоуровневые кеши и модифицированные строки

При многоуровневом кэше грязные строки кэша могут распространяться вверх по иерархии. Таким образом, линия может быть в измененном состоянии в L1D и L2 одного и того же ядра. Это нормально, потому что обратная запись из L1D проходит через L2.

Насколько я понимаю, совместно используемый инклюзивный кэш L3 в процессорах Intel не должен выполнять обратную запись в DRAM, прежде чем он сможет совместно использовать копии строки кэша для нескольких ядер. Итак, что касается нормального / простого MESI, думайте о L3 как о резервном хранилище, а не о DRAM.

Заставить эту работу на системах с несколькими сокетами сложно; Я не уверен, что все настроено так, что L3 в сокете может кэшировать только физические адреса, которые соответствуют DRAM, подключенному к этому сокету. В любом случае запросы snoop отправляются между сокетами при пропадании кэша L3, и есть множество сложных настроек, которые вы можете настроить для настройки этого в системе Xeon. (См. Статью Anandtech о Haswell Xeon, например.)

На шаге 1, прежде чем ядро 2 сможет пометить линию как измененную, оно должно уведомить ядро ​​1. Таким образом, на шаге 2 линия больше не находится в ядре 1 L1D. Таким образом, на шаге 2, прежде чем получить доступ к линии, ядро ​​1 должно получить обновленное значение от ядра 2.

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