Обратите внимание, что 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 в некоторый буфер слияния.