Как маркируется кэш микроопераций?

3

Согласно статье Real World Technologies о микроархитектуре Intel Sandy Bridge :

«Кэш-память мопов Sandy Bridge организована в 32 набора и 8 способов, по 6 мопов на линию, что в сумме составляет 1,5 тыс. Мопов. Кэш UOP строго включен в кэш команд L1. Каждая строка также содержит метаданные, включая количество допустимых значений uops в строке и длину инструкций x86, соответствующих строке кэша uop. Каждое окно 32B, отображаемое в кэш UOP, может охватывать 3 из 8 путей в наборе, максимум до 18 моп - примерно 1,8 Б / моп. Если окно 32B имеет более 18 мопов, оно не может поместиться в кеш мопов и должно использовать традиционный внешний интерфейс. Микрокодированные инструкции не хранятся в кэше UOP, а вместо этого представлены указателем на ПЗУ микрокода и, возможно, первыми несколькими мопами ».

«Каждое окно 32B (из кэша команд) отображается в кэш UOP, может охватывать 3 из 8 способов набора»

Итак, предположим, что у нас есть окно команд 32B, которое было бы половиной строки кэша команд L1, в этой строке будут отличаться только биты смещения, но биты тега и набора будут одинаковыми для всех байтов в строке.

После того как 32-байтовое окно было декодировано, мопы вводятся в кэш мопов с тем же виртуальным адресом, который использовался для извлечения 16-байтового блока выборки из кеша команд L1 (чтобы их можно было параллельно исследовать на каждом поле 32B)

Это говорит о том, что эти мопы могут охватывать 3 из 8 способов в наборе, но это будет означать, что они должны будут иметь одинаковые биты набора, но разные биты тега, чтобы в конечном итоге оказаться в одном наборе (то есть они не были бы включены та же самая строка в кеше L1I), означает ли это, что кэш мопов расположен немного по-другому, один виртуальный адрес в начале строки, и мопы просто заполняются следующим способом в наборе и следующим способом в установлен. Как гарантируется, что следующее окно инструкций 32B, которое все еще будет иметь тот же тег и те же самые биты, но разные биты смещения (2-я половина строки 64 B в L1I) отображается на 4-й путь этого набора.

Постулат : путь кеша uop помечен физическим тегом виртуального индекса, следующий путь - ничем, третий - ничем, четвертый - виртуальным индексом / физическим тегом, где разница в том, что смещение изменилось с 0 на 32, поэтому, по сути, способ может быть выбран с использованием разных битов смещения, в отличие от способа, которым тег L1I кэшируется: биты смещения функционируют как смещение для строки кэша.

Кто-нибудь может уточнить расположение кэшей UOP или как на самом деле работает эта маркировка?

Льюис Келси
источник
Обратите внимание, что AMD Zen также имеет кэш UOP, но о его внутренних компонентах известно меньше. Итак, вы спрашиваете конкретно о UOP-кэше Intel в семействе Sandybridge. Согласно тестированию Агнера Фога ( agner.org/optimize , в частности, его микроархив pdf), он практически адресован (VIVT), сохраняя время ожидания / мощность поисков iTLB.
Питер Кордес

Ответы:

1

Обратите внимание, что AMD Zen также имеет кэш UOP, но о его внутренних компонентах известно меньше. Итак, вы спрашиваете конкретно о UOP-кэше Intel в семействе Sandybridge.

Согласно тестированию Агнера Фога ( https://www.agner.org/optimize/ , в частности, его микроархив pdf), он фактически адресован (VIVT), сохраняя время ожидания / мощность поисков iTLB для попаданий в uop-кэш. И, тем не менее, позволяя по-прежнему очень тесно интегрировать iTLB с кешем L1i, как обычно для кеша VIPT L1.

(также связано: какой метод отображения кэша используется в процессоре Intel Core i7? для краткого изложения этого и других кэшей и https://stackoverflow.com/tags/x86/info для дополнительных ссылок на производительность / uarch.)

После того, как 32-байтовое окно было декодировано

Здесь вы ошиблись в своем мыслительном процессе.

Кэш мопов кэширует только те мопы, которые декодируются по пути (спекулятивного) выполнения. Инструкции x86 могут быть правильно декодированы, только если вы знаете правильную начальную точку. Байты после безусловного jmpмогут вообще не быть началом инструкции.

Кроме того, вы не хотите загрязнять кэш-память uop множеством однобайтовых инструкций заполнения между функциями (например, 0x90 NOP или 0xcc int3используется MSVC). Или вообще, с «холодными» инструкциями, которые не достигаются во время обычного выполнения после выбранной ветви. "Строка" / путь uop-кэша рано заканчивается безусловным переходом или с call.

Устаревшие декодеры являются либо инструкциями декодирования, которые ЦП ожидает фактически выполнить ( направляя их в кэш-память uop для повторного использования позже, а IDQ напрямую для использования сразу), либо они отключаются . В отличие от P4, унаследованные декодеры не являются слабыми; они похожи на декодеры в Core2 / Nehalem, поэтому выполнение из L1i в целом нормально, за исключением высокопроизводительного кода с большим средним размером команд. Им не нужно пытаться «строить следы» заранее. (Кэш uop в любом случае не является кэшем трассировки; он не следует за переходами. Но в любом случае он не пытается заполнить кэш uop для всех 32 байтов инструкций, которые могут быть кэшированы сразу.)

Но что интересно, Агнер говорит: « Один и тот же фрагмент кода может иметь несколько записей в кэше μop, если в нем есть несколько записей перехода ».


Мое лучшее предположение о том, как на самом деле работает механизм поиска в кэше:

Имеется 64-битный виртуальный адрес для извлечения кода из:

  • Младшие 5 битов являются смещением относительно 32-байтовой границы.
  • Следующие 5 битов являются индексом. Не 6 бит для 64-байтовых линий L1i; извлечение из кэша UOP напрямую не заботится об этом.
  • Старшие биты (до бита 48) являются тегом.

Используйте 5-битный индекс для выбора набора.
Получите все 8 способов из этого набора (тег + метаданные, а также данные параллельно, потому что это высокопроизводительный кеш).

Сравните параллельно для всех 8 способов:

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

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

Это догадки, основанные на том, как работает кэш uop и когда он выбрасывает пути. Но это может помочь вам получить полезную мысленную модель этого.


Обратите внимание, что адрес не обязательно должен быть выровнен по 16 байтов. Он должен эффективно поддерживать несоответствующие цели ветвления, а также прямой код с границами команд, которые не совпадают с 32-байтовыми границами. (Насколько я могу судить, инструкции, которые пересекают 32-байтовую границу, кэшируются в порядке uop-cache для начального адреса команды, даже если она заканчивается в следующей строке кэша L1i через 64-байтовую границу.)

Блоки извлечения / предварительного декодирования L1i для длины команды выровнены, но полное декодирование в унаследованных декодерах работает до 16 байтов любого выравнивания, взятого из очереди между предварительным декодированием и декодированием. Выравнивание точек входа в цикл по определенным границам выравнивания менее важно, чем раньше.


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

Кэш-память uop не может одновременно кэшировать оба пути, поэтому при обнаружении этого ЦПУ должен обратиться к устаревшим декодерам и выбросить пути кэша uop для этого блока 32B (который он уже обнаружил с помощью компаратора тегов).

Затем он может начать повторное заполнение uop-кэша, поскольку он декодирует мопы с этой точки.

Аналогичная ситуация происходит, когда 3 пути уже заполнены, но в одном и том же блоке 32B машинного кода x86 имеется больше мопов. Uop-кеш выбрасывает все 3 пути для этого блока. (Я не уверен, что он помнит, чтобы не пытаться кэшировать их в следующий раз, или он просто создает кэш каждый раз и выбрасывает его, когда достигает предела, например, в цикле с 20 однобайтовыми nopинструкциями. )

Посмотрите выравнивание ветвей для циклов, включающих микрокодированные инструкции на процессорах семейства Intel SnB для некоторых подробностей об этом случае . Обратите внимание, что микрокодированные инструкции, такие как divиспользование целого пути кеша uop самостоятельно, могут легко привести к заполнению всех трех способов и запуску переключателей DSB-to-MITE (переключатели кеш-uop к устаревшим декодерам могут создать 1 цикл пузыря в переднем конце).

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

Также обратите внимание, что процессоры Intel до Skylake могут добавлять только 4 мопа в IDQ из кеша мопов, но почему-то не ставят узкое место, когда в кеше мопов есть пути с 3 или 6 мопами вместо 4. Так что IDK, если есть какой-то буферизации для не разветвляющейся выборки UOP. Это немного загадки. Можно ожидать, что fetch будет идти по схеме 4, 2, 4, 2, если выборка выполняется из полных строк по 6 моп каждый, но мы не видим такого узкого места во внешнем интерфейсе, как для циклов, запущенных из кеша uop с 2 -байтовые инструкции вроде xor eax,eax. Корпорация Intel заявила, что кэш-память uop может извлекать мопы только с одного пути за цикл, поэтому, возможно, ограничение в 4 мегапикселя только для добавления в IDQ, а не для чтения из кеша uop в некоторый буфер слияния.

Питер Кордес
источник
Спасибо за это, обратите внимание: «Код передается из двойного буфера в декодеры в блоках, которые я буду называть блоками IFETCH (блоками выборки команд). Блоки IFETCH имеют длину до 16 байтов. В большинстве случаев блок выборки команд заставляет каждый блок IFETCH начинаться с границы инструкции, а не с 16-байтовой границы. ' - микроархитектура.pdf. Для пояснения он указывает «до 16 байтов», означает ли это, что он всегда гарантирует, что он содержит полные инструкции, поэтому, если 5,5,4,4, он может упаковать первые 3 вместе и отправить его в виде 14-байтового блока и следующие 4 начнутся в новом блоке ..?
Льюис Келси
..так что пропускная способность блока извлечения не всегда 16 байтов
Льюис Келси
@LewisKelsey: о, я забыл, что перед предварительным декодированием была буферизация, но имеет смысл повысить пропускную способность и получить больше от энергозатратного оборудования, которое ограничено 16 байтами. В любом случае, помните, что ЦП не знает, где заканчиваются инструкции, до окончания предварительного декодирования, или если прогнозирование ветвлений говорит о том, что ветвление занято, то конец его известен. Но в противном случае внешний интерфейс будет подавать 16 байтов в предварительные декодеры. Если последний байт является серединой insn, то начало следующего блока предварительного декодирования будет началом этой инструкции (он будет зависать до следующего цикла).
Питер Кордес
@LewisKelsey: Во всяком случае, да, предварительное декодирование должно найти конец инструкции, прежде чем она сможет отправить ее декодерам. Но части руководства Uarch Agner Fog, в которых упоминаются блоки IFETCH, являются разделами до Core2. Он говорит, что Core2 добавил очередь между предсказанием ветвлений и выборкой команд. Но он все еще говорит: « Любая инструкция, которая пересекает 16-байтовую границу, будет оставлена ​​до тех пор, пока не будет обработан следующий 16-байтовый блок », поэтому предварительное декодирование все еще основано на выровненных блоках. (Но декодирование - нет, даже в более ранних процессорах.) Интересный факт: до SnB декодеры могли делать до 7 мопов (4-1-1-1). SnB = 4.
Питер Кордес
Спасибо, еще один полезный ресурс: intel.co.uk/content/dam/www/public/us/en/documents/manuals/…
Льюис Келси,