Что происходит с IFU и внешним интерфейсом, когда инструкция отсутствует в L1I? - PullRequest
0 голосов
/ 05 ноября 2018

Во-первых, когда IFU выдает запрос на 16 байтов, это взаимодействие с L1I изменяется / фиксируется таким образом, что, когда L1I получает адрес от IFU, он впоследствии генерирует 16 байтов подряд или IFU должен отправить адреса всех 16 байтов, как при традиционном доступе к кешу?

Чтобы добраться до сути, предположим, что IFU извлекает инструкции на границах, выровненных по 16B, и вдруг виртуальный индекс (и я предполагаю, что виртуальный индекс действительно логический виртуальный, а не линейный виртуальный - не совсем уверен; я знаю, с L1D AGU обрабатывает смещения сегментации) промахов в кэше L1i.

Что будет точно ? (Примечание: пример CPU Skylake с топологией кольцевой шины)

Будет ли отключен внешний интерфейс, когда декодеры закончат декодировать то, что было до него, как это будет сделано? Во-вторых, какой тип согласования / разговора существует между IFU и кешем L1I, есть промах, кеш должен информировать IFU, чтобы он прекратил извлекать инструкции? Возможно, кэш ожидает получения данных снизу и, как только это произойдет, выдает данные в IFU или IFU ожидает в состоянии спин-блокировки и продолжает попытки чтения?

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

  • L1I кеш отсутствует, ITLB хит.
  • Контроллер кэша L1I выделяет буфер заполнения строки
  • Контроллер кеша L1I запрашивает у L2 и передает ему физический адрес (эти операции не конфликтуют с операциями аппаратных предварительных сборщиков, потому что все обращения к кешу должны быть последовательными или помещаться в очередь, как я себе представляю)
  • L2 miss, передает адрес в срез LLC
  • LLC ломтик мисс
  • Кеширующий агент отправляет адрес домашнему агенту
  • Домашний агент не обнаруживает ядер с данными
  • Домашний агент отправляет адрес контроллеру памяти
  • Контроллер памяти преобразует адрес в кортеж (канал, димм, ранг, микросхема, чип, группа банков, банк, строка, столбец) и выполняет соответствующее отображение, чередование, генерацию команд и т. Д.
  • Теперь, поскольку это DDR4, он собирается вернуть 128 байтов, но для упрощения предположим, что сейчас это DDR3, поэтому 64 байта. 64 байта отправляются обратно домашнему агенту, я предполагаю, что все это хранится в порядке очереди, поэтому домашний агент знает, какому адресу соответствуют данные.
  • Домашний агент отправляет данные кеширующему агенту, опять же, я полагаю, что кеширующий агент, возможно, сохраняет некоторое количество невыполненных промахов, чтобы знать, что его нужно отправить выше
  • Данные передаются в L2, не знаю, как L2 знает, что ему нужно подняться выше, но вы идете
  • Контроллер L2 передает информацию в L1, и L1 опять-таки каким-то образом знает, в какой буфер заполнения строки вводить запрошенную строку кэша и что ему требуется тег F (пересылка).
  • IFU либо поднимает его в состоянии спин-блокировки, либо с IFU * происходит некоторое согласование

Если у кого-то есть дополнительная информация об этом процессе и он может просветить меня, пожалуйста, дайте мне знать.

1 Ответ

0 голосов
/ 05 ноября 2018

Интересный вопрос, как только вы преодолеете некоторые заблуждения (см. Мои комментарии к вопросу).

Выборка / декодирование происходит строго в программном порядке. Нет механизма для декодирования блока из более поздней строки кэша в ожидании пропуска L1i, даже для заполнения uop-кэша. Насколько я понимаю, кэш-память uop всегда заполняется только инструкциями, которые ЦП ожидает выполнить на текущем пути выполнения.

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


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

Но да, промах L1i создает пузырь в конвейере, который длится до тех пор, пока данные не поступят из L2. Каждое ядро ​​имеет собственный частный L2 для каждого ядра, который заботится о том, чтобы отправлять запросы вне ядра, если он пропускает L2. WikiChip показывает , путь данных между L2 и L1i имеет ширину 64 байта в Skylake-SP.

https://www.realworldtech.com/haswell-cpu/6/ показывает, что L2 <-> L1d имеет ширину 64 байта в Haswell и более поздних версиях, но не показывает столько деталей для выборки инструкций. (Что часто не является узким местом, особенно для циклов малого и среднего размера, которые попадают в кэш UOP.)

Есть очереди между извлечением, предварительным декодированием (границами команд) и полным декодированием, которые могут скрывать / поглощать эти пузырьки и иногда мешать им достигать декодеров и фактически снижать пропускную способность декодирования. И есть большая очередь (64 мопа на Skylake), которая передает этап выпуска / переименования, называемый IDQ. Инструкции добавляются в IDQ из кэша UOP или из устаревшего декодирования. (Или, когда непрямое выполнение микрокода для команды, которая занимает более 4 мопов, достигает передней части IDQ, выпускает / переименовывает выборки непосредственно из ПЗУ секвенсора микрокода для таких инструкций, как rep movsb или lock cmpxchg.)

Но когда у сцены нет входных данных, да, она отключается. Нет "спин-блокировки"; он не управляет эксклюзивным доступом к общему ресурсу, он просто ожидает на основе сигнала управления потоком.

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


Контроллер кэша L1I выделяет буфер заполнения строки

L2-> L1i использует буферы, отличные от 10 LFB, которые используют кэш-память L1d / хранилища NT. Эти 10 предназначены для связи между L1d и L2.

Блок-схема Skylake-SP на WikiChip показывает 64-байтовый тракт данных от L2 до L1i, отдельный от L2-> L1d с его 10 LFB.

L2 должен управлять наличием нескольких устройств чтения и записи (кэши L1 и данные в / из L3 в его буферах SuperQueue). @ HadiBrais комментирует о том, что мы знаем, что L2 может обрабатывать 2 попадания за такт, но количество пропусков за такт, за которое он может обрабатывать / генерировать запросы L3, менее ясно.

Хади также прокомментировал: L2 имеет один считывающий 64-байтовый порт для L1i и один двунаправленный 64-байтовый порт с L1d. Он также имеет порт для чтения / записи (64-байтовый в Skylake, 32-байтовый в Haswell) со срезом L3, к которому он подключен. Когда контроллер L2 получает строку от L3, он немедленно записывает ее в соответствующую запись (или записи) супер очереди.

Я не проверил первоисточник для этого, но мне это кажется правильным.


Извлечение из DRAM происходит с пакетной передачей 64 байтов (1 строка кэша) за один раз . Не только 16 байтов (128 бит)! Можно выполнить код из «не кэшируемой» области памяти, но обычно вы используете области памяти WB (с обратной записью), которые можно кэшировать.

AFAIK, даже DDR4 имеет размер пакета 64 байта, а не 128 байтов.

Я предполагаю, что все это хранится в порядке очереди, поэтому домашний агент знает, какому адресу соответствуют данные.

Нет, контроллер памяти может переупорядочивать запросы на локальность на странице DRAM (не то же самое, что страница виртуальной памяти).

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

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

@ HadiBrais прокомментировал: запросы в L2 должны быть помечены идентификатором отправителя. Запросы в L3 должны быть помечены еще одним идентификатором отправителя. Запросы на L1I не должны быть помечены.

Хади также обсудил тот факт, что L3 должен обрабатывать запросы от нескольких ядер за цикл. Архитектура кольцевой шины в центральных процессорах до Skylake-SP / SKX означала, что максимум 3 запроса могли приходить на один срез L3 за такт (по одному в каждом направлении на кольце и один от подключенного к нему ядра). Если бы они все были для одной и той же строки кэша, было бы определенно выгодно удовлетворить их всех одной выборкой из этого среза, так что это может быть то, что делают срезы кэш-памяти L3.


См. Также Ульрих Дреппер Что каждый программист должен знать о памяти? , чтобы узнать больше о кеше и особенно о DDR DRAM. Статья Wikipedia SDRAM также объясняет, как работают пакетные передачи целых строк кэша от DRAM .

Я не уверен, действительно ли процессоры Intel передают смещение в пределах строки кэша для критического первого слова и раннего перезапуска для резервного копирования иерархии кэша. Думаю, нет, потому что некоторые из ближайших к ядру путей данных намного шире, чем 8 байтов, а в Skylake - 64 байта.

См. Также микроарху Agner Fog pdf (https://agner.org/optimize/), и другие ссылки в вики-теге x86 .

...