Наборно-ассоциативный кэш
Наборно-ассоциативный кэш (англ. set-associative cache) — это тип кэш-памяти, в котором каждая строка основной памяти может быть размещена в ограниченном, фиксированном множестве строк кэша, называемом набором (set). Данный подход является компромиссом между кэшем прямого отображения (direct-mapped cache) и полностью ассоциативным кэшем (fully associative cache), обеспечивая баланс между скоростью поиска, сложностью аппаратной реализации и вероятностью промахов (cache misses).
Принцип работы
В наборно-ассоциативном кэше память делится на блоки (строки) фиксированного размера. Кэш, в свою очередь, организован в виде матрицы: строки кэша сгруппированы в наборы, каждый из которых содержит определённое число «путей» (ways). Количество путей в наборе обозначается как n и определяет ассоциативность кэша (например, 2-путевой, 4-путевой, 8-путевой кэш).
Адрес памяти, по которому происходит обращение, делится на три части:
- Смещение (offset) — указывает на конкретный байт внутри блока.
- Индекс (index) — определяет номер набора в кэше, в который может быть помещён блок.
- Тег (tag) — уникальный идентификатор, позволяющий различать блоки, хранящиеся в одном наборе.
При обращении к памяти процессор вычисляет индекс набора, затем параллельно сравнивает теги всех путей в этом наборе с тегом запрашиваемого адреса. Если совпадение найдено — происходит попадание (cache hit), и данные из соответствующей строки передаются процессору. Если совпадения нет — происходит промах (cache miss), и блок данных загружается из основной памяти в одну из свободных строк данного набора (или замещает одну из существующих в соответствии с алгоритмом замещения).
Классификация по ассоциативности
Наборно-ассоциативные кэши классифицируются по числу путей в наборе:
- Кэш прямого отображения (1-путевой) — каждый набор состоит из одной строки. Это частный случай наборно-ассоциативного кэша с ассоциативностью 1. Простейший в реализации, но страдает от конфликтных промахов (когда два часто используемых блока отображаются в один и тот же набор).
- 2-путевой кэш — каждый набор содержит две строки. Уменьшает количество конфликтных промахов по сравнению с прямым отображением.
- 4-путевой, 8-путевой, 16-путевой кэш — более высокая ассоциативность. Снижает вероятность промахов, но увеличивает сложность схем сравнения тегов и энергопотребление.
- Полностью ассоциативный кэш — частный случай, когда все строки кэша образуют один набор. Максимальная гибкость, но требует сложной схемы параллельного сравнения всех тегов, что ограничивает размер кэша.
На практике наиболее распространены кэши с ассоциативностью от 2 до 16 путей. Выбор конкретного значения зависит от целевого применения, бюджета транзисторов и требований к производительности.
История и развитие
Концепция кэш-памяти была впервые предложена Морисом Уилксом в 1965 году в статье «Slave Memories and Dynamic Storage Allocation». Ранние реализации кэшей (например, в IBM System/360 Model 85, 1968 год) использовали полностью ассоциативную организацию, что было оправдано при небольших объёмах кэша (до нескольких килобайт).
С ростом размеров кэш-памяти (десятки и сотни килобайт) полностью ассоциативные схемы стали слишком дорогими из-за необходимости большого количества компараторов. В 1970-х годах начали применяться кэши прямого отображения, однако они показали высокую частоту конфликтных промахов. Наборно-ассоциативная архитектура, впервые реализованная в микропроцессорах в 1980-х годах (например, Intel 80486 использовал 8-килобайтный 4-путевой наборно-ассоциативный кэш), стала стандартом де-факто для современных процессоров.
Устройство и аппаратная реализация
Основные компоненты наборно-ассоциативного кэша:
- Массив тегов (tag array) — хранит теги для каждой строки кэша. Для каждого набора имеется n ячеек тегов.
- Массив данных (data array) — хранит собственно кэшированные блоки данных. Организован аналогично массиву тегов.
- Схема декодирования индекса — выбирает нужный набор на основе битов индекса адреса.
- Набор компараторов — параллельно сравнивает теги выбранного набора с тегом запроса. Количество компараторов равно числу путей.
- Мультиплексор — выбирает данные из того пути, где тег совпал (или из пути, выбранного алгоритмом замещения при промахе).
- Управляющая логика — реализует алгоритмы замещения (LRU, псевдо-LRU, случайный, FIFO) и обновления состояния кэша.
Аппаратная сложность растёт линейно с увеличением числа путей, так как требуется больше компараторов и более широкая шина мультиплексора. Это увеличивает площадь кристалла, задержку доступа и энергопотребление.
Алгоритмы замещения
При промахе кэша необходимо решить, какую из строк в выбранном наборе заместить новым блоком. Основные алгоритмы:
- LRU (Least Recently Used) — замещается строка, к которой дольше всего не было обращений. Обеспечивает хорошую локальность, но требует хранения информации о порядке использования для каждого набора (для n-путевого кэша — n! состояний, что сложно для n>4).
- Псевдо-LRU — аппроксимация LRU с меньшим числом состояний (например, с использованием битовой матрицы или дерева). Часто применяется в кэшах с ассоциативностью 8 и выше.
- Случайный (Random) — замещается случайная строка из набора. Прост в реализации, но может приводить к неоптимальной производительности.
- FIFO (First In, First Out) — замещается строка, загруженная раньше всех. Не учитывает частоту обращений.
В современных процессорах (например, Intel Core, AMD Ryzen) для кэшей L1 и L2 обычно используется псевдо-LRU, а для кэша L3 — более сложные алгоритмы, иногда с учётом частоты обращений (adaptive replacement policy).
Применение
Наборно-ассоциативные кэши используются во всех современных микропроцессорах общего назначения (x86, ARM, RISC-V), графических процессорах (GPU), микроконтроллерах, а также в системах на кристалле (SoC). Конкретные параметры кэша (размер, ассоциативность, размер строки) варьируются в зависимости от уровня иерархии:
- Кэш L1 (обычно 32–64 КБ на ядро) — часто 4–8-путевой, с размером строки 64 байта. Ориентирован на минимальную задержку (2–4 такта).
- Кэш L2 (256 КБ – 1 МБ на ядро) — 8–16-путевой, с задержкой 10–20 тактов.
- Кэш L3 (несколько мегабайт, общий для всех ядер) — 16–20-путевой, иногда с использованием кольцевой шины (ring bus) для доступа.
В процессорах Intel (начиная с архитектуры Nehalem, 2008 год) и AMD (начиная с Zen, 2017 год) кэш L3 является неинклюзивным, то есть не обязательно содержит копии данных из L1/L2, что позволяет эффективнее использовать доступную площадь кристалла.
Преимущества и недостатки
Преимущества:
- Более низкая вероятность конфликтных промахов по сравнению с кэшем прямого отображения.
- Меньшая аппаратная сложность и задержка по сравнению с полностью ассоциативным кэшем.
- Возможность масштабирования путём увеличения числа путей.
Недостатки:
- Более высокая сложность и энергопотребление по сравнению с прямым отображением.
- При фиксированном размере кэша увеличение ассоциативности уменьшает количество наборов, что может увеличить вероятность промахов при плохой локальности.
- Алгоритмы замещения (особенно LRU) требуют дополнительных ресурсов.
Интересные факты
- В процессорах ARM Cortex-A78 (2020 год) используется 32-килобайтный 4-путевой кэш L1 для данных и 32-килобайтный 4-путевой кэш L1 для инструкций.
- В суперкомпьютерах и серверных процессорах (например, Intel Xeon Platinum 9200) кэш L3 может достигать 77 МБ при ассоциативности 20–24 пути.
- В некоторых встраиваемых системах (например, на базе ARM Cortex-M) кэш отсутствует вовсе, так как программы и данные хранятся непосредственно в SRAM или Flash-памяти.
- Исследования показывают, что для большинства рабочих нагрузок увеличение ассоциативности свыше 8–16 путей даёт незначительный прирост производительности, но существенно увеличивает площадь и энергопотребление.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →