Протокол MESI в согласованности кеша

Операционная система

предисловие

В процессоре с несколькими ядрами каждое ядро ​​имеет свой собственный кеш, и как обеспечить согласованность содержимого кеша нескольких ядер — проблема, с которой легко столкнуться.Протокол MESI — это специальный протокол A для решения согласованности кеша. Многие процессоры используют протокол MESI или вариант протокола MESI, а протокол MESI на самом деле является вариантом протокола MSI. Протокол MESI использует стратегию обратной записи для обновления кэша, что еще больше повышает его производительность, но также несет дополнительные риски.Проблем, вызванных обратной записью, можно избежать, используя барьеры памяти при написании программ.

Введение в протокол MESI

Происхождение названия протокола MESI состоит из четырех описанных им состояний кэша, а именно M (модифицированный), E (монопольный), S (общий) и I (недействительный). Описание каждого состояния выглядит следующим образом:

государство описывать
Modified Содержимое текущего кеша допустимо, данные были изменены и не согласуются с данными в памяти, данные существуют только в текущем кеше
Exclusive Содержимое текущего кеша допустимо, данные согласуются с данными в памяти, и данные существуют только в текущем кеше.
Shared Содержимое текущего кеша допустимо, данные согласуются с данными в памяти, и данные существуют в нескольких кешах.
Invalid Текущий кеш недействителен

переход состояния

Протокол МЭСИ фактически является конечным автоматом, состояние кеша будет передаваться в зависимости от воздействия внешних событий, а конкретные события делятся на две категории: запрос процессора к кешу и запрос шины к кешу:

  1. PrRd: процессор запросил чтение блока кэша.
  2. PrWr: процессор запросил запись блока кеша
  3. BusRd: запрос Snooper указывает, что другой процессор запросил чтение блока кэша.
  4. BusRdX: запрос отслеживания указывает, что другой процессор запросил запись в блок кэша, которым процессор не владеет.
  5. BusUpgr: запрос отслеживания указывает, что другой процессор запросил запись блока кэша, принадлежащего этому процессору.
  6. Flush: запрос Snooper указывает, что запрос состоит в том, чтобы записать весь кеш обратно в основную память.
  7. FlushOpt: запрос отслеживания, чтобы указать, что весь блок кэша отправляется на шину для отправки другому процессору (копия из кэша в кэш)

Переход между состояниями происходит следующим образом:

Переходы состояний, вызванные операциями процессора
начальное состояние действовать отклик
Invalid(I) PrRd
  • Отправьте сигнал BusRd на шину
  • Другие процессоры видят BusRd, проверяют себя на наличие действительной копии данных и уведомляют запрашивающий кеш.
  • Если другой кэш имеет действительную копию, состояние переходит в (S)Shared
  • Если никакой другой кэш не имеет действительной копии, состояние переходит в (E)Exclusive
  • Если в других кэшах есть действительные копии, один из кэшей выдает данные, в противном случае он получает данные из основной памяти.
PrWr
  • Отправить сигнал BusRdX на шину
  • Переход состояния в (M)Modified
  • Если в других кэшах есть действительные копии, один из кэшей выдает данные, в противном случае он получает данные из основной памяти.
  • Если другие кэши имеют действительные копии, сделайте их копии недействительными, увидев сигнал BusRdX.
  • Запишите измененное значение в блок кеша
Exclusive(E) PrRd
  • Нет генерации автобусных транзакций
  • Статус остается прежним
  • Операция чтения является попаданием в кэш
PrWr
  • Нет генерации автобусных транзакций
  • Переход состояния в (M)Modified
  • Запишите измененное значение в блок кеша
Shared(S) PrRd
  • Нет генерации автобусных транзакций
  • Статус остается прежним
  • Операция чтения является попаданием в кэш
PrWr
  • Сигнал автобусной транзакции BusUpgr
  • Переход состояния в (M)Modified
  • Другие кэши видят сигнал шины BusUpgr и помечают свои копии как (I)Invalid.
Modified(M) PrRd
  • Нет генерации автобусных транзакций
  • Статус остается прежним
  • Операция чтения является попаданием в кэш
PrWr
  • Нет генерации автобусных транзакций
  • Статус остается прежним
  • Операция записи является попаданием в кеш
Переходы состояний, вызванные различными операциями шины
начальное состояние действовать отклик
Invalid(I) BusRd
  • Состояние остается прежним, сигнал игнорируется
BusRdX/BusUpgr
  • Состояние остается прежним, сигнал игнорируется
Exclusive(E) BusRd
  • статус становится общим
  • Сигнализируем шину FlushOpt и выдаем содержимое блока
BusRdX
  • статус становится недействительным
  • Сигнализируем шину FlushOpt и выдаем содержимое блока
Shared(S) BusRd
  • статус становится общим
  • Возможно сигнализировать шине FlushOpt и выдавать содержимое блока (время разработки определяет, какой общий кеш выдает данные)
BusRdX
  • статус становится недействительным
  • Возможно сигнализировать шине FlushOpt и выдавать содержимое блока (время разработки определяет, какой общий кеш выдает данные)
Modified(M) BusRd
  • статус становится общим
  • Выдать сигнал шины FlushOpt и выдать содержимое блока, получателем является кэш и контроллер основной памяти, который первоначально выдал BusRd (обратная запись в основную память)
BusRdX
  • статус становится недействительным
  • Выдать сигнал шины FlushOpt и выдать содержимое блока, получателем является кэш и контроллер основной памяти, который первоначально выдал BusRd (обратная запись в основную память)

Введение барьеров памяти

Конструкция МЭСИ относительно проста и понятна, но есть два места, которые приведут к падению производительности: во-первых, при обновлении кэша в недействительном состоянии необходимо попытаться получить самые свежие данные из других ЦП или даже из памяти; во-вторых, необходимо сделать кэш недействительным. Дождитесь подтверждения от других ЦП; эти две операции занимают много времени, и если ЦП будет продолжать ждать во время этих двух процессов, это будет пустой тратой времени.

store buffer

Чтобы уменьшить задержку записи в кэш в недействительном состоянии, можно ввести буфер сохранения. Поскольку операция записи произойдет в любом случае, ЦП сначала отправит сигнал, чтобы уведомить другие ЦП о сбое кеша, а затем обновит эту операцию записи в буфер сохранения и подождет, пока другие ЦП подтвердят получение сигнала перед отправкой. результат записываю в память.

Это позволяет избежать трудоемкого ожидания подтверждения другим процессором при обновлении кеша, но также приводит к тому, что обновление процессора не записывается в кеш вовремя, поэтому, когда процессору необходимо прочитать кеш, ему необходимо подтвердить, есть ли есть ли необходимость в хранении буфера данных, этот механизм называется переадресацией хранилища. Стоит отметить, что когда ЦП читает и записывает собственный буфер хранилища, соответствующие изменения данных не воспринимаются другими ЦП.

invalidate queue

Когда ЦП получает сообщение об аннулировании кеша, ожидается, что ЦП немедленно выполнит аннулирование. Но на самом деле, процессор не сразу выполняет операцию инвалидации, а сначала отправляет сообщение для подтверждения получения, а затем добавляет операцию инвалидации в очередь инвалидации, и операция в очереди затем будет выполнена в соответствующее время ( не обязательно сразу). Причина, по которой необходима очередь аннулирования, также заключается в том, что операция аннулирования является дорогостоящей, и ЦП должен отбросить кеш, чтобы выполнить операцию аннулирования, что приводит к снижению частоты попаданий в кэш. Преимущество этого в том, что это может повысить производительность ЦП, но также приводит к возможности просроченных данных в кэше.

барьер памяти

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

Барьеры памяти делятся на барьеры записи и барьеры чтения.При написании программ вы можете добавлять барьеры памяти там, где это необходимо. Барьер записи заставит процессор очистить содержимое буфера хранения, то есть все изменения будут записаны в кеш, а затем изменения будут записаны в память, делая ее видимой для других процессоров; барьер чтения будет заставить ЦП выполнять все недействительные в операции очереди недействительных, чтобы сделать недействительным содержимое собственного кэша, чтобы ЦП получал последние данные кэша из памяти или другого ЦП.

разное

На первый взгляд, протокол MESI чем-то похож на модель памяти и ключевое слово volatile в java, и позже он будет подробно раскрыт.