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

443
Lewis Kelsey

Согласно статье 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 или как на самом деле работает эта маркировка?

3
Обратите внимание, что AMD Zen также имеет кэш UOP, но о его внутренних компонентах известно меньше. Так что вы спрашиваете конкретно о UOP-кэше Intel в семействе Sandybridge. Согласно тестированию Агнера Фога (https://www.agner.org/optimize/, в частности, его микроархив pdf), он фактически адресован (VIVT), сохраняя время ожидания / мощность поисков iTLB. Peter Cordes 5 лет назад 0

1 ответ на вопрос

1
Peter Cordes

Обратите внимание, что 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 начнутся в новом блоке ..? Lewis Kelsey 5 лет назад 0
..так что пропускная способность от блока выборки не всегда 16 байтов Lewis Kelsey 5 лет назад 0
@LewisKelsey: о, я забыл, что перед предварительным декодированием была буферизация, но имеет смысл повысить пропускную способность и получить больше от энергозатратного оборудования, которое ограничено 16 байтами. В любом случае, помните, что ЦП не знает, где заканчиваются инструкции до * после * предварительного декодирования, или если прогнозирование ветвлений говорит о том, что ветвление занято, то конец его известен. Но в противном случае внешний интерфейс будет подавать 16 байтов в предварительные декодеры. Если последний байт является серединой insn, то начало следующего блока предварительного декодирования будет началом этой инструкции (он будет зависать до следующего цикла). Peter Cordes 5 лет назад 0
@LewisKelsey: В любом случае, перед декодированием необходимо найти * конец * инструкции, прежде чем она сможет отправить ее декодерам. Но части руководства Uarch Agner Fog, в которых упоминаются блоки IFETCH, являются разделами до Core2. Он говорит, что Core2 добавил очередь между предсказанием ветвлений и выборкой команд. Но он все еще говорит: «* Любая инструкция, которая пересекает 16-байтовую границу, будет оставлена ​​до тех пор, пока не будет обработан следующий 16-байтовый блок. *», Поэтому предварительное декодирование все еще основано на выровненных блоках. (Но декодирование - нет, даже в более ранних процессорах.) Интересный факт: до SnB декодеры могли делать до 7 мопов (4-1-1-1). SnB = 4. Peter Cordes 5 лет назад 0
Спасибо, еще один полезный ресурс: https://www.intel.co.uk/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf. Lewis Kelsey 5 лет назад 0

Похожие вопросы