Как кэши данных маршрутизируют объект в этом примере?

Рассмотрим диаграмму архитектуры данных. (Искусство ASCII следует.)

  --------------------------------------
  | CPU core A | CPU core B |          |
  |------------|------------| Devices  |
  |  Cache A1  |  Cache B1  | with DMA |
  |-------------------------|          |
  |         Cache 2         |          |
  |------------------------------------|
  |                RAM                 |
  --------------------------------------

Предположим, что

  • объект затенен на грязной линии кэша A1,
  • более старая версия того же объекта затеняется на чистой строке Cache 2, и
  • новейшая версия того же объекта была недавно записана в RAM через DMA.

Диаграмма:

  --------------------------------------
  | CPU core A | CPU core B |          |
  |------------|------------| Devices  |
  |  (dirty)   |            | with DMA |
  |-------------------------|          |
  |     (older, clean)      |          |
  |------------------------------------|
  |          (newest, via DMA)         |
  --------------------------------------

Три вопроса, пожалуйста.

  1. Что произойдет, если процессорное ядро ​​A попытается загрузить (прочитать) объект?

  2. Если же процессорное ядро ​​A попытается сохранить (записать) объект, что произойдет?

  3. Произошло бы что-нибудь неочевидное, интересное и / или иное, если бы вместо ядра A ядро ​​B выполняло загрузку или хранение?

Мои вопросы теоретические. Мои вопросы не относятся к какой-либо конкретной архитектуре процессора, но вы можете обратиться к x86 или ARM (или даже RISC-V) в своем ответе, если хотите.

Заметки. Если игнорирование отслеживания упростит ваш ответ, то вы можете игнорировать отслеживание по своему усмотрению. Кроме того, вы можете изменить проблему, если, по вашему мнению, измененная проблема лучше осветит тему. Если вы должны написать код для ответа, то я бы предпочел C/C++. Насколько мне известно, вам не нужно указывать конкретные флаги протокола MESI или MOESI в своем ответе, но более простого, менее подробного ответа, вероятно, будет достаточно.

Мотив. Мой мотив спросить, что я читаю о параллелизме и модели памяти в стандарте C++. Я хотел бы научиться визуализировать эту модель примерно с точки зрения аппаратных операций, если это возможно.

ОБНОВИТЬ

В той степени, в которой я понимаю, @HadiBrais рекомендует, чтобы следующая схематичная архитектура была более обычной, чем та, которую я ранее схематизировал, особенно если реализован DDIO (см. Его ответ ниже).

  --------------------------------------
  | CPU core A | CPU core B | Devices  |
  |------------|------------| with DMA |
  |  Cache A1  |  Cache B1  |          |
  |------------------------------------|
  |              Cache 2               |
  |------------------------------------|
  |                RAM                 |
  --------------------------------------

1 ответ

Решение

Кажется, ваша гипотетическая система включает в себя когерентные кэши L1 с обратной записью и некогерентные DMA. Очень похожим реальным процессором является ARM11 MPCore, за исключением того, что он не имеет кэш-памяти второго уровня. Однако большинство современных процессоров имеют согласованный DMA. В противном случае ответственность за обеспечение согласованности лежит на программном обеспечении. Состояние системы, показанное на вашей диаграмме, уже является непоследовательным.

Что произойдет, если процессорное ядро ​​A попытается загрузить (прочитать) объект?

Он просто прочитает строку, хранящуюся в локальном кэше L1. Никаких изменений не произойдет.

Если же процессорное ядро ​​A попытается сохранить (записать) объект, что произойдет?

Строки уже находятся в состоянии M-когерентности в кеше L1 ядра A. Таким образом, он может записывать в него напрямую. Никаких изменений не произойдет.

Произошло бы что-нибудь неочевидное, интересное и / или иное, если бы вместо ядра A ядро ​​B выполняло загрузку или хранение?

Если ядро ​​B выдало запрос на загрузку к той же строке, кэш L1 ядра A будет отслежен, и строка будет найдена в состоянии M. Строка обновляется в кэше L2 и отправляется в кэш L1 ядра B. Также произойдет одно из следующего:

  • Строка считается недействительной из кэша L1 ядра А. Линия вставляется в кэш L1 ядра B в состоянии E-когерентности (в случае протокола MESI) или в состоянии S-когерентности (в случае протокола MSI). Если L2 использует отслеживающий фильтр, фильтр обновляется, чтобы указать, что ядро ​​B имеет линию в состоянии E/S. В противном случае состояние линии в L2 будет таким же, как и в ядре L1 ядра B, за исключением того, что он не знает, что он там есть (поэтому прослушивание будет передаваться всегда).
  • Состояние линии в кеше L1 ядра A изменяется на S. Строка вставляется в кэш L1 ядра B в состоянии S-когерентности. L2 вставляет строку в состояние S.

В любом случае, и кэш-память L1, и кэш-память L2 будут содержать одну и ту же копию строки, которая остается несовместимой с копией в памяти.

Если ядро ​​B выдало запрос на сохранение для той же строки, строка будет признана недействительной из кэша ядра A и окажется в состоянии M в кэше ядра B.

В конце концов, строка будет удалена из иерархии кэша, чтобы освободить место для других строк. Когда это происходит, есть два случая:

  • Строка находится в состоянии S/E, поэтому она будет просто удалена из всех кэшей. Позже, если строка будет прочитана снова, копия, записанная операцией DMA, будет считана из основной памяти.
  • Строка находится в состоянии M, поэтому она будет записана обратно в основную память и (возможно, частично) перезапишет копию, записанную операцией DMA.

Очевидно, что такое бессвязное состояние никогда не должно происходить. Это можно предотвратить, сделав недействительной всю соответствующую строку из всех кэшей до того, как начнется операция записи DMA, и убедившись, что ни одно ядро ​​не получит доступ к области памяти, в которую производится запись, до завершения операции. Контроллер DMA отправляет прерывание всякий раз, когда операция завершается. В случае операции чтения DMA все соответствующие строки должны быть записаны обратно в память, чтобы обеспечить использование самых последних значений.

Технология Intel Data Direct I / O (DDIO) позволяет контроллеру DMA выполнять чтение или запись непосредственно из общего кэша последнего уровня для повышения производительности.


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

Все коммерческие процессоры x86 полностью согласованы с кэшем (т. Е. Вся иерархия кэша согласована). Чтобы быть более точным, все процессоры в одной и той же области разделяемой памяти являются когерентными. Кроме того, все коммерческие многоядерные сопроцессоры x86 (т.е. Intel Xeon Phi в виде карты PCIe) внутренне полностью согласованы. Сопроцессор, который является устройством в соединении PCIe, не связан с другими сопроцессорами или процессорами. Таким образом, сопроцессор находится в отдельной области когерентности. Я думаю, это потому, что нет встроенного аппаратного механизма для создания устройства PCIe, которое имеет кэш-память, согласованную с другими устройствами PCIe или процессорами.

Помимо коммерческих чипов x86, существуют прототипы чипов x86, которые не связаны с кэшем. Единственный пример, который мне известен, - это однокристальный облачный компьютер Intel (SCC), который позднее превратился в целостный Xeon Phi.

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