Как осуществляется доступ к кэш-памяти данных AMD с микрометками L1?

#caching #x86 #cpu-architecture #cpu-cache #amd-processor

#кэширование #x86 #архитектура процессора #cpu-cache #amd-процессор

Вопрос:

Я изучаю процесс доступа к кешу L1 процессора AMD. Но я неоднократно читал руководство AMD и все еще не могу его понять.

Мое понимание кэша данных L1 в Intel таково:
кэш L1 является виртуальным, индексируемым и помеченным физическими тегами. Поэтому используйте биты индекса виртуального адреса, чтобы найти соответствующий набор кешей и, наконец, определить, какая строка кэша в наборе кешей основана на теге.
(Intel делает свои кеши L1d достаточно ассоциативными и достаточно маленькими, чтобы биты индекса приходили только из смещения внутри страницы, которое являетсято же самое с физическим адресом. Таким образом, они получают скорость VIPT без каких-либо проблем с псевдонимами, действуя как PIPT.)

Но AMD использовала новый метод. В Zen 1 у них есть 32-Кбайт 8-полосный ассоциативный кэш L1d, который (в отличие от 64-КБ 4-полосного L1i) достаточно мал, чтобы избежать проблем с наложением псевдонимов без микрометок.
Из руководства AMD по оптимизации программного обеспечения 2017 года, раздел 2.6.2.2 «Микроархитектура процессоров семейства AMD 17h» (Zen 1):

Теги кэша данных L1 содержат микрометки на основе линейных адресов (utag), которые помечают каждую кэш-линию линейным адресом, который использовался для доступа к кэш-линии изначально. Нагрузки используют этот utag для определения способа чтения кэша, используя свой линейный адрес, который доступен до определения физического адреса загрузки через TLB. Utag — это хэш линейного адреса загрузки. Этот линейный поиск на основе адресов позволяет очень точно предсказать, каким образом находится кэш-линия, до чтения данных кэша. Это позволяет загрузке считывать только один способ кэширования, а не все 8. Это экономит электроэнергию и уменьшает конфликты банков.

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

Линейное наложение происходит, когда два разных линейных адреса сопоставляются с одним и тем же физическим адресом. Это может привести к снижению производительности при загрузке и хранении в кэш-линиях с псевдонимами. При загрузке адреса, который действителен в DC L1, но под другим линейным псевдонимом, будет отображаться ошибка DC L1, что требует выполнения запроса кэша L2. Задержка, как правило, будет не больше, чем при попадании в кэш L2. Однако, если одновременно выполняется несколько загрузок или хранилищ с псевдонимами, в каждом из них могут возникать пропуски постоянного тока L1, поскольку они обновляют utag определенным линейным адресом и удаляют другой линейный адрес из возможности доступа к кэш-цепочке.

Также возможно, что два разных линейных адреса, которые НЕ связаны с одним и тем же физическим адресом, конфликтуют в utag, если они имеют одинаковый линейный хэш. При заданном индексе постоянного тока L1 (11:6) в любое время доступна только одна строка кэша с заданным линейным хэшем; любые строки кэша с соответствующими линейными хэшами помечены как недопустимые в utag и недоступны.


  1. Utag может ошибаться в обоих направлениях

Каков конкретный сценарий этого предложения во втором абзаце? При каких обстоятельствах попадание будет предсказано как промах, а промах — как попадание? Когда центральный процессор обращается к данным из памяти в кэш, он вычисляет способ кэширования на основе utag. И просто положить его сюда? Даже если другой способ кэширования пуст?

  1. Линейное наложение происходит, когда два разных линейных адреса сопоставляются с одним и тем же физическим адресом.

Как разные линейные адреса могут отображаться на один и тот же физический адрес?

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

Что означает это предложение? Я понимаю, что сначала нужно вычислить utag на основе линейного адреса (виртуального адреса), чтобы определить, какой способ кэширования использовать. Затем используйте поле тега физического адреса, чтобы определить, является ли это попаданием в кэш? Как обновляется utag? Будет ли это записано в кэш?

  1. любые строки кэша с соответствующими линейными хэшами помечены как недопустимые в utag и недоступны. Что означает это предложение?

Как AMD оценивает попадание или промах кэша? Почему некоторые попадания считаются промахами? Кто-нибудь может объяснить? Большое спасибо!

Комментарии:

1. (2) Например, вы можете mmap (MAP_SHARED) один и тот же файл на два разных виртуальных адреса. Таблицы страниц сопоставляют линейные (виртуальные) адреса с физическими адресами и не обязательно должны быть уникальными. Ядра очень часто имеют несколько сопоставлений для одной и той же страницы, например, Linux напрямую сопоставляет всю физическую оперативную память, а также создает другие сопоставления ядра ( kernel.org/doc/Documentation/x86/x86_64/mm.txt ), или сопоставляет их с адресным пространством процесса пользовательского пространства. Таким образом, каждая используемая вами страница имеет как минимум два сопоставления в таблицах страниц.

Ответ №1:

Теги кэша данных L1 содержат микрометки на основе линейных адресов (utag), которые помечают каждую кэш-линию линейным адресом, который использовался для доступа к кэш-линии изначально.

С каждой строкой кэша в L1D связан utag. Это означает, что структура памяти utag организована точно так же, как в L1D (т. Е. 8 способов и 64 набора), и между записями существует взаимно однозначное соответствие. Utag вычисляется на основе линейного адреса запроса, который вызвал заполнение строки в L1D.

Нагрузки используют этот utag для определения способа чтения кэша, используя свой линейный адрес, который доступен до определения физического адреса загрузки через TLB.

Линейный адрес загрузки отправляется одновременно в предиктор пути и в TLB (лучше использовать термин MMU, поскольку существует несколько TLB). Конкретный набор в памяти utag выбирается с использованием определенных битов линейного адреса (11: 6), и все 8 utag в этом наборе считываются одновременно. Между тем utag вычисляется на основе линейного адреса запроса на загрузку. По завершении обеих этих операций данный utag сравнивается со всеми utag, сохраненными в наборе. Память utag поддерживается таким образом, что в каждом наборе может быть не более одного utag с одинаковым значением. В случае попадания в память utag предиктор пути предсказывает, что целевая строка кэша находится в соответствующей записи кэша в L1D. До этого момента физический адрес еще не нужен.

Utag — это хэш линейного адреса загрузки.

Хэш-функция была переработана в статье под названием Take A Way: изучение последствий для безопасности предикторов пути кэширования AMD в разделе 3 для ряда микроархитектур. По сути, определенные биты линейного адреса в позициях 27: 12 преобразуются друг в друга, чтобы получить 8-битное значение, которое является utag. Хорошая хэш-функция должна: (1) минимизировать количество пар линейных адресов, которые сопоставляются с одним и тем же utag, (2) минимизировать размер utag и (3) иметь задержку, не превышающую задержку доступа к памяти utag.

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

Помимо памяти utag и связанной с ней логики, L1D также включает в себя память тегов и память данных, все они имеют одинаковую организацию. В памяти тегов хранятся физические теги (бит 6 до старшего бита физического адреса). В памяти данных хранятся строки кэша. В случае попадания в utag предиктор пути соответствующим образом считывает только одну запись в памяти тегов и памяти данных. Размер физического адреса на современных процессорах x86 превышает 35 бит, поэтому размер физического тега превышает 29 бит. Это более чем в 3 раза больше, чем размер utag. Без прогнозирования пути в кэше с более чем одним способом кэширования несколько тегов должны были бы считываться и сравниваться параллельно. В 8-полосном кэше чтение и сравнение 1 тега потребляет гораздо меньше энергии, чем чтение и сравнение 8 тегов.

В кэше, где каждый способ может быть активирован отдельно, каждая запись в кэше имеет свою собственную строку слов, которая короче по сравнению с мировой строкой, разделяемой несколькими способами кэширования. Из-за задержек в распространении сигнала чтение одним способом занимает меньше времени, чем чтение 8 способами. Однако в кэше с параллельным доступом задержка прогнозирования невозможна, но линейное преобразование адресов становится критическим для задержки загрузки. С помощью прогнозирования пути данные из прогнозируемой записи могут быть предположительно перенаправлены в зависимые uop. Это может обеспечить значительное преимущество в задержке загрузки, тем более что задержка линейного преобразования адресов может варьироваться из-за многоуровневой структуры MMU, даже в типичном случае попадания MMU. Недостатком является то, что это приводит к новой причине, по которой могут возникать повторы: в случае неправильного прогнозирования может потребоваться воспроизведение десятков или даже сотен операций ввода-вывода. Я не знаю, действительно ли AMD пересылает запрошенные данные перед проверкой прогноза, но это возможно, хотя и не упоминается в руководстве.

Уменьшение конфликтов банков является еще одним преимуществом прогнозирования путей, как указано в руководстве. Это означает, что в разные банки помещаются разные способы. В разделе 2.6.2.1 говорится, что биты 5: 2 адреса, размер доступа и номер пути кеширования определяют банки, к которым будет осуществляться доступ. Это предполагает, что существует 16 * 8 = 128 банков, по одному банку на каждый 4-байтовый блок в каждом случае. Биты 5: 2 получены из линейного адреса загрузки, размер загрузки получен из uop загрузки, а номер пути получен из предиктора пути. В разделе 2.6.2 говорится, что L1D поддерживает две 16-байтовые загрузки и одно 16-байтовое хранилище в одном цикле. Это означает, что каждый банк данных имеет один 16-байтовый порт чтения-записи. Каждый из 128 банковских портов подключен через межсоединение к каждому из 3 портов памяти данных L1D. Один из 3 портов подключен к буферу хранилища, а два других — к буферу загрузки, возможно, с промежуточной логикой для эффективной обработки перекрестных нагрузок (один uop загрузки, но два запроса загрузки, результаты которых объединяются), перекрывающихся нагрузок (чтобы избежать конфликтов банков) и нагрузок, которые пересекаютсяграницы банка.

Тот факт, что для прогнозирования путей требуется доступ только к одному пути в памяти тегов и памяти данных L1D, позволяет уменьшить или полностью устранить необходимость (в зависимости от того, как обрабатываются snoops), чтобы сделать память тегов и данных действительно многопортовой (именно такого подхода Intel придерживалась в Haswell), сохраняя при этомдостигается примерно та же пропускная способность. Тем не менее, конфликты банков все еще могут возникать при одновременном доступе к одному и тому же пути и идентичным битам адреса 5: 2, но разным utags. Прогнозирование пути уменьшает конфликты банков, поскольку не требует чтения нескольких записей (по крайней мере, в памяти тегов, но, возможно, также и в памяти данных) для каждого доступа, но это не устраняет конфликты банков полностью.

При этом для обработки проверок заполнения (см. Позже), проверок проверки (см. Позже), отслеживания и проверки «нормального пути» для обращений без нагрузки может потребоваться настоящая мультипортация. Я думаю, что только запросы на загрузку используют предиктор пути. Другие типы запросов обрабатываются нормально.

Высокоточное предсказание попадания / промаха L1D может иметь и другие преимущества. Если прогнозируется, что загрузка в L1D будет пропущена, сигнал пробуждения планировщика для зависимых операций ввода-вывода может быть подавлен, чтобы избежать вероятных повторов. Кроме того, физический адрес, как только он станет доступен, может быть отправлен в кэш L2 до полного разрешения прогноза. Я не знаю, используются ли эти оптимизации AMD.

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

В ОС, которая поддерживает несколько линейных адресных пространств или допускает использование синонимов в одном и том же адресном пространстве, строки кэша можно однозначно идентифицировать только с использованием физических адресов. Как упоминалось ранее, при поиске utag в памяти utag может быть одно совпадение или ноль совпадений. Рассмотрим сначала случай попадания. Этот линейный поиск на основе адресов приводит к спекулятивному попаданию и все еще нуждается в проверке. Даже если подкачка отключена, utag все равно не является уникальной заменой полного адреса. Как только MMU предоставит физический адрес, прогноз может быть проверен путем сравнения физического тега из предсказанного способа с тегом из физического адреса доступа. Может произойти один из следующих случаев:

  1. Физические теги совпадают, и предположительное попадание считается истинным попаданием. Ничего не нужно делать, кроме, возможно, запуска предварительной выборки или обновления состояния замены строки.
  2. Физические теги не совпадают, и целевая строка не существует ни в одной из других записей того же набора. Обратите внимание, что целевая строка не может существовать в других наборах, поскольку все запоминающие устройства L1D используют одну и ту же функцию индексации набора. Я расскажу, как это делается позже.
  3. Физические теги не совпадают, и целевая строка существует в другой записи того же набора (связанной с другим utag). Я расскажу, как это делается позже.

Если в памяти utag не было найдено совпадающего utag, не будет физического тега для сравнения, поскольку невозможно предсказать. Может произойти один из следующих случаев:

  1. Целевая строка фактически не существует в L1D, поэтому предположительный промах является истинным промахом. Строка должна быть извлечена откуда-то еще.
  2. Целевая строка фактически существует в том же наборе, но с другим utag. Я расскажу, как это делается позже.

(Здесь я делаю два упрощения. Во-первых, предполагается, что запрос на загрузку относится к кэшируемой памяти. Во-вторых, при предположительном или истинном попадании в L1D ошибки в данных не обнаружены. Я пытаюсь сосредоточиться на разделе 2.6.2.2.)

Доступ к L2 необходим только в случаях 3 и 5, а не в случаях 2 и 4. Единственный способ определить, в чем дело, — сравнить физический тег загрузки с физическими тегами всех существующих строк в том же наборе. Это можно сделать либо до, либо после доступа к L2. В любом случае, это необходимо сделать, чтобы избежать возможности наличия нескольких копий одной и той же строки в L1D. Выполнение проверок перед доступом к L2 увеличивает задержку в случаях 3 и 5, но ухудшает ее в случаях 2 и 4. Выполнение проверок после доступа к L2 улучшает задержку в случаях 2 и 4, но ухудшает ее в случаях 3 и 5. Можно одновременно выполнять проверки и отправлять запрос на L2. Но это может привести к потере энергии и пропускной способности L2 в случаях 3 и 5. Похоже, что AMD решила выполнить проверки после извлечения строки из L2 (которая включает в себя кеши L1).

Когда строка поступает из L2, L1D не нужно ждать, пока она будет заполнена, чтобы ответить запрошенными данными, поэтому более высокая задержка заполнения допустима. Теперь сравниваются физические теги, чтобы определить, какой из 4 случаев произошел. В случае 4 строка заполняется в памяти данных, памяти тегов и памяти utag способом, выбранным политикой замены. В случае 2 запрошенная строка заменяет существующую строку, у которой оказался тот же utag, и политика замены не используется для выбора способа. Это происходит, даже если в том же наборе была свободная запись, что существенно снижает эффективную емкость кэша. В случае 5 utag можно просто перезаписать. Случай 3 немного сложнее, поскольку он включает запись с соответствующим физическим тегом и другую запись с соответствующим utag. Один из них должен быть признан недействительным, а другой должен быть заменен. В этом случае также может существовать свободная запись, которая не используется.

Линейное наложение происходит, когда два разных линейных адреса сопоставляются с одним и тем же физическим адресом. Это может привести к снижению производительности при загрузке и хранении в кэш-линиях с псевдонимами. При загрузке адреса, который действителен в DC L1, но под другим линейным псевдонимом, будет отображаться ошибка DC L1, что требует выполнения запроса кэша L2. Задержка, как правило, будет не больше, чем при попадании в кэш L2. Однако, если одновременно выполняется несколько загрузок или хранилищ с псевдонимами, в каждом из них могут возникать пропуски постоянного тока L1, поскольку они обновляют utag определенным линейным адресом и удаляют другой линейный адрес из возможности доступа к кэш-цепочке.

Именно так может произойти случай 5 (и случай 2 в меньшей степени). Линейное наложение псевдонимов может происходить в одном и том же линейном адресном пространстве и в разных адресных пространствах (при этом задействуются эффекты переключения контекста и гиперпоточности).

Также возможно, что два разных линейных адреса, которые НЕ связаны с одним и тем же физическим адресом, конфликтуют в utag, если они имеют одинаковый линейный хэш. При заданном индексе постоянного тока L1 (11:6) в любое время доступна только одна строка кэша с заданным линейным хэшем; любые строки кэша с соответствующими линейными хэшами помечены как недопустимые в utag и недоступны.

Именно так могут возникать случаи 2 и 3, и они обрабатываются, как обсуждалось ранее. В этой части говорится, что L1D использует простую функцию индексации набора; установленное число равно битам 11: 6.

Я думаю, что большие страницы повышают вероятность возникновения случаев 2 и 3, потому что более половины битов, используемых хэш-функцией utag, становятся частью смещения страницы, а не номера страницы. Физическая память, разделяемая между несколькими процессами ОС, повышает вероятность случая 5.