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

Рассмотрим схематическую архитектуру кэша данных. (Далее следует искусство ASCII.)

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

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

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

Диаграмма:

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

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

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

  2. Что произойдет, если вместо этого ядро ​​ЦП A попытается сохранить (записать) объект?

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

Мои вопросы теоретические. Мои вопросы не относятся к какой-либо конкретной архитектуре ЦП, но вы можете сослаться на 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                 |
  --------------------------------------

person thb    schedule 11.02.2019    source источник
comment
Что вы имеете в виду под затененным? Кроме того, ваш пример предполагает, что вы предполагаете, что DMA некогерентен. Чтобы прояснить, это сделано намеренно?   -  person Hadi Brais    schedule 12.02.2019
comment
@HadiBrais Чтобы прояснить уровень, с которого задается вопрос: я разработчик Debian, имеющий образование в области электротехники. Моя профессиональная сфера - это не компьютеры, а строительство зданий, поэтому в компьютерных вопросах я в основном обучаюсь самостоятельно. Если затененный - неправильное слово, пожалуйста, поправьте меня! Что касается DMA, я действительно предполагал, что DMA некогерентен, но PCI и тому подобное мне не очень хорошо известны. Я упомянул DMA только для упрощения проблемы. (В противном случае проблема могла бы потребовать четырех ядер ЦП и трехуровневого кеша, что излишне усложняло.)   -  person thb    schedule 12.02.2019
comment
В частности, чтобы ответить на ваш первый вопрос, говоря «затенять X», я имею в виду временное сохранение несовершенно синхронизированной, возможно, изменяемой копии X для локального использования и, если необходимо, для последующей очистки.   -  person thb    schedule 12.02.2019
comment
Современная x86 имеет DMA с когерентным кешем. Я думаю, что это стало делом, когда процессоры x86 начали размещать контроллер памяти на кристалле, поэтому отслеживание тегов L3 на пути к памяти стало практичным (а включающие теги L3 Intel работают как фильтр отслеживания для частных кешей по ядрам). Наличие согласованного DMA, вероятно, упрощает реализацию агрессивной аппаратной предварительной выборки, не беспокоясь о создании декогеренции в нечетных угловых случаях неверных предсказаний ветвления, ведущих к нежелательной спекулятивной загрузке из только что очищенной памяти.   -  person Peter Cordes    schedule 13.02.2019


Ответы (1)


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

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

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

Что произойдет, если вместо этого ядро ​​ЦП A попытается сохранить (записать) объект?

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

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

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

  • Строка признана недействительной из кэша L1 ядра A. Строка вставляется в кэш 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, которые не связаны с кешем. Единственный известный мне пример - это одночиповый облачный компьютер (SCC) от Intel. , который позже превратился в когерентный Xeon Phi.

person Hadi Brais    schedule 12.02.2019
comment
+1 Вы осветили мои заблуждения. Приветствуется освещение. Освещение полезно. Я не знал, что моя система запустилась в запрещенном состоянии! - person thb; 12.02.2019
comment
@thb: иметь копию (older, clean) в L2 невозможно, если она грязная в L1d. Как говорит Хади, это уже бессвязно. Но не только с оперативной памятью, но и между уровнями кеш-памяти. MESI требует, чтобы если строка в любом кэше находится в измененном (грязном) состоянии, все в других кешах он недействителен. (Обычно строка не записывается обратно до тех пор, пока она не будет удалена из L1, поэтому мы получаем Modified в L2 и Invalid в других L1. Но есть механизм, позволяющий внутренним кешам читать копии грязной строки L2 до того, как она действительно написано обратно.) - person Peter Cordes; 13.02.2019
comment
Чистый исходный MESI предназначен для поддержания согласованности отдельных кешей (например, нескольких ядер, каждое со своими собственными частными кешами), а не иерархии с общим кешем последнего уровня. Вот почему он говорит о слежении за шиной памяти. (Я собирался опубликовать предыдущий комментарий по этому вопросу, но поместите его здесь на тот случай, если Хади захочет обновить ответ, чтобы решить эту проблему с начальным состоянием, которое выходит за рамки некогерентности DMA в недопустимые состояния MESI, я думаю.) - person Peter Cordes; 13.02.2019
comment
@PeterCordes Я интерпретировал (older, clean), поскольку линия существует в состоянии E. Реализация может проверить, что если L2 имеет линию в состоянии E или M, то он должен отслеживать все частные кеши. Также в другой реализации MESI может быть реализован только на L1, а SI может быть реализован на включающем L2. В этом случае, если какое-либо ядро ​​пропускает свой частный кеш и попадает в L2, оно должно всегда отслеживать все частные кеши. Это менее эффективно, но требует меньше оборудования на уровне L2. Если L2 не является включающим, необходимо отправлять слежение, есть ли попадание или промах в L2 ... - person Hadi Brais; 13.02.2019
comment
... Протокол MESI в основном имеет значение только тогда, когда вы нажимаете L1. Если OP намеревался иметь MESI в L2 и означал, что линия там находится в состоянии S, то это действительно некогерентно, потому что другое ядро ​​могло прочитать устаревшую версию в L2 (кроме некогерентного DMA). - person Hadi Brais; 13.02.2019
comment
Почему в системе должны быть согласованные кеши? Возможно ли иметь некогерентный общий L2 между ядрами, не так ли? Intel SCC - что-то в этом роде (правда, у него нет общего кеша между ядрами). - person Margaret Bloom; 13.02.2019
comment
@MargaretBloom Несогласованные кеши, безусловно, могут быть. Существуют настоящие процессоры с некогерентным L1 (но L2 общий и, следовательно, обязательно согласованный), но я не помню их названий. Тем не менее, я не думаю, что этот вопрос был бы интересен, если бы вся система была некогерентной, потому что в такой системе поведение было бы в основном неопределенным, если бы она когда-либо достигла некогерентного состояния (то есть, когда два ядра используют одно и то же строка, и по крайней мере один из них пишет в нее). Система будет просто непоследовательной, и не будет никаких гарантий, какое значение окажется в памяти. - person Hadi Brais; 13.02.2019
comment
Интересный пример карт Xeon Phi в штатной системе. Это хороший пример для Безопасно ли mov + mfence на NUMA?, где ответ вращается вокруг того факта, что все многоядерные системы x86 имеют кэш. -согласованные, иначе они не могут быть единым системным образом, на котором работает обычное программное обеспечение x86. Я добавил там абзац со ссылкой на пример Xeon Phi. (Пинг @MargaretBloom) - person Peter Cordes; 14.02.2019