# Архитектура компьютера ## Лекция 13 ## Кеш Пенской А.В., 2026 --- ## Кеш. Назначение. Предпосылки
Кеш
промежуточный буфер с быстрым доступом, содержащий информацию, которая может быть запрошена с наибольшей вероятностью.
-------------------- 1. Малый объём быстрой памяти для текущих данных. 1. Целесообразен, если доступ к памяти неравномерный. 1. (реже) Смена интерфейса: процессор — кеш — память.
Временная и пространственная локальность данных 
---- ### Кеши в компьютерных системах
Кеши применяются на всех уровнях компьютерных систем, но мы обсуждаем процессоры. Противоречие: 1. Много данных, низкая локальность. Нужен очень большой кеш. 1. Мало данных, высокая локальность. Нужен очень маленький кеш.
 
--- ### Кеш. Функционирование
1. Кеш состоит из набора кеш-линий (блоков кеша, записей). 1. Кеш-линия ассоциирована с элементом в медленной памяти. 1. Кеш-линия имеет идентификатор (тег), определяющий соответствие. 1. Доступ к памяти реализуется прозрачно для программиста. 1. Память может быть изменена вне зависимости от кеша: DMA, другое ядро.
 
---- #### Кеш. Чтение данных 1. **Тег найден** $\rightarrow$ **кеш-попадание (cache hit)**. Данные читаются в процессор из кеш-линии. 1. **Тег не найден** $\rightarrow$ **кеш-промах (cache miss)**. Запрашиваем данные из памяти или следующего кеша. Выбираем линию для замещения: - Есть пустая — подходит. - Все заняты — принимаем решение о вытеснении линии. - Длительность получения данных — произвольна, т.к.: - возможен многоуровневый кеш; - возможна блокировка памяти (восстановление памяти, DMA).
**Уровень попадания (hit rate)** — основная характеристика эффективности кеша.

---- #### Кеш. Запись данных (кеш попадание) 1. **Немедленная запись** (write-through). Изменение вызывает синхронное обновление памяти. Иногда медленнее, чем без кеша. 2. **Отложенная запись** (write-back). Обновление памяти при вытеснении кеш-линии, периодически, или по запросу. - Требует хранения признака модификации ("грязный"). - Группировка изменений, сокрытие промежуточных состояний. - Возможно неконсистентное состояние кеша и памяти. Для процессора — невидимое, для других устройств (DMA) — требуется принудительная запись. 3. **Гибридные варианты**. Пример: немедленная запись с буферизацией. ---- #### Кеш. Запись данных (кеш промах) 1. **Запись с размещением** (Write Allocate, Fetch on Write). - Данные загружаются в кеш, после в них вносится исправление. - Два обращения: запись вытесняемого и чтение необходимого. - Поведение аналогично промаху по чтению. 1. **Запись без размещения** (No-Write Allocate, Write Around). - Запись производится напрямую в память или через буфер (группировка изменений). ---- #### Кеш-промахи. Разная информация и операции
1. **Чтение данных**.
Средняя задержка. Может компенсироваться параллелизмом уровня инструкций (см. суперскаляр). 1. **Запись данных**.
Минимальная задержка. Запись может быть отложена. 1. **Чтение инструкций**
Большая задержка. Процессор простаивает в ожидании инструкции.

---- ## HyperThreading For each processor core that is physically present, the operating system addresses two virtual (logical) cores and shares the workload between them when possible. The main function of hyper-threading is to increase the number of independent instructions in the pipeline. Relevance to cache: two logical cores share the physical cache — higher utilization, but also higher contention and eviction pressure.  --- ## Кеш. Внутреннее устройство Кеш — это память и логика. Логика реализует: 1. Поиск кеш-линии по тегу (компараторы). 1. Вытеснение, replacement (определение ненужной кеш-линии). 1. Предзагрузка (prefetch) данных и инструкций. 1. Взаимодействие с памятью (группировка операций и т.п.). 1. Синхронизации кешей разных уровней. Больше данных $\longrightarrow$ больше логики. Масштабирование по времени или по площади: - 2 линии, 2 компаратора $\longrightarrow$ 1 такт, - 2 линии, 1 компаратор $\longrightarrow$ 2 такта. --- ### Кеш. Ассоциативность Политика размещения данных памяти в кеше для оптимизации поиска. Аналогия: поиск в `array` $O(n)$, `btree` $O(log(n))$, `hashmap` $\Theta(1)-O(n)$.
```text address, 32 bit 011001010101101001101001010101010 ^ high low ^ | | | | +-- 2 Gb step 1 byte step --+ ```

Тег — идентификатор области памяти, сохранённой в кеш-линии: 1. **Полный** адрес — много памяти, много больших компараторов. 1. **Младшие биты**. Не нужны, если работать блоками, а не байтами. 1. **Средние биты**. Циклически повторяются в адресах памяти. - Принцип временной и пространственной локальности. 1. **Старшие биты**. Относительно уникальны (если используются). ---- #### Полностью ассоциативный кеш
(Fully Associative Cache) Любая строка памяти может быть отображена в любую кеш-линию.
1. Лучшая эффективность. 1. Очень много логики: - компараторы, - вытеснение. 

---- #### Кеш с прямым отображением (Direct Mapping) Каждая ячейка может быть отображена только в 1 кеш-линию.
(одна кеш-линия — много ячеек)
Средняя часть — номер линии. 1. Меньше памяти для tags. 1. Один меньший компаратор. 1. Нет вытеснения (однозначно). 1. Коллизия и техническая выгрузка. 

---- #### Множественно-ассоциативный кеш
(N-Way Set Associative Cache) Кеш с прямым отображением (1 банк), воспроизведённый N раз.
1. Больше ассоциативность, ниже скорость, выше эффективность. 1. Выбор банка осуществляется на основе алгоритма вытеснения. 

--- ### Кеш. Вытеснение и замещение
1. Ключевой механизм: эвристика выбора более не требующейся кеш-линии среди доступных. 1. В процессорах применяются достаточно простые алгоритмы (скорость и площадь): - Least Recently Used (LRU) - Pseudo-LRU 1. Возможные модификации: - Victim Cache — сперва отделить, потом вытеснить - Запрет кеширования
#### Least Recently Used Маркировка записей временем последнего доступа Пример: `A B C _D_ E _D_ F` | | | | | |:--------:|:--------:|:--------:|:--------:| | **A(0)** | | | | | A(0) | **B(1)** | | | | A(0) | B(1) | **C(2)** | | | A(0) | B(1) | C(2) | **D(3)** | | | | | | | **E(4)** | B(1) | C(2) | D(3) | | E(4) | B(1) | C(2) | **D(5)** | | E(4) | **F(6)** | C(2) | D(5) | | | | | |
----
#### Pseudo-LRU 1. Бинарное дерево: - вершины хранят путь: `left(0) / right(1)`; - листья: кеш-линии. 1. Поиск записи для вставки или вытеснения: - спуск по дереву согласно значениям в вершинах; - инверсия всех пройдённых вершин. 1. Кеш попадание — инверсия пути от корня до листа. 1. Значительно "легче" LRU.
 `A B C _D_ E _D_ F`
--- ### Многоуровневый кеш 
Свойства кеша определяются: - технологией ячеек памяти, - устройством кеша (размер, ассоциативность, и т.д.).
Задачи кеша: 1. Повышение скорости доступа. 1. Синхронизация проц. ядер. 1. Оптимизация интерфейсов.
Способы организации многоуровневых кешей: 1. Разделённый/унифицированный 1. Включающие/исключающие 1. Частные/общие ---- #### Разделённый (Banked)
/Унифицированный (Unified) Кеш-память может быть реализована одним или несколькими банками памяти. Иметь один канал доступа, или несколько.
Принцип разделения: - По типу данных: - Кеш данных. - Кеш инструкций. - Trace cache (микрокод). - По процессорному ядру.  
1. Достоинства разделённого кеша: - Повысить скорость доступа (больше каналов). - Адаптировать устройство кеша под специфику использования. 1. Недостатки разделённого кеша: - Усложнение процессора. - Конфликты между банками кеш-памяти.
---- #### Включающие (Inclusive)
/Исключающие (Exclusive) Должен ли кеш одного уровня включать кеш другого уровня?
1. **Инклюзивная** — данные кеш-линий дублируются. Доступ происходит быстрее (выгрузка `L1` не может привести к выгрузке `L2`), но часть памяти "теряется". 2. **Эксклюзивная** — данные не дублируются. Память используется эффективнее. 3. Гибридный вариант
(**Non-Inclusive, Non-Exclusive** — NINE) — гибридные варианты.
 (О когерентности позднее)
---- #### Частный (Private)/Общий (Shared) Характеризует доступ процессорных ядер к кешу.
1. **Частный** кеш — ядро имеет эксклюзивный доступ к кешу. - Скорость доступа ядра. - Дублирование и конфликты. 1. **Общий** кеш — несколько ядер имеет доступ к кешу. - Меньше кеш промахов. - Нет дублирования. - Постоянная синхронизация доступа.

---- #### Уровни кеширования в процессорах
- **L0** (опция) — специальный кеш для: стека, int/float чисел. Обычно доступен за такт. - **L1** — быстрый, неотъемлемая часть процессора. Обычно разделён (Banked). - **L2** — обычно часть процессора. От 128 Кбайт до 1-12 Мбайт. Обычно общий (Shared). - **L3** до 24 Мбайт и более. Синхронизация данных в многоядерных процессорах. - **L4** (экзотика для серверов и мейнфреймов). Оптимизация интерфейса доступа к памяти.

--- ### Кеш. Когерентность
Целостность данных в кешах процессора и памяти. **Проблема**: параллельный доступ к данным (чтение/запись) множеством акторов (процессорные ядра, DMA). 

---- #### Пример состояний кеш-линий (MOESI) 1. **Модифицировано** (**M**odified). `L` — свежие уникальные данные. - Модификация возможна без запросов. - `L` $\rightarrow$ `Exclusive` (запись в память). 1. **Владелец** (**O**wned). Только одна запись в состоянии. - `L` — свежие данные, `C` — возможны, `M` — может устареть. - `L` $\rightarrow$ `Modified` ($\forall$ `C` $\rightarrow$ `Invalid`) или $\rightarrow$ `Shared` (запись в память). 1. **Эксклюзивное** (**E**xclusive). `L`, `M` — свежие данные, `C` — нет. - `L` $\rightarrow$ `Modified` (запись в кеш) или `L` $\rightarrow$ `Invalid` в любой момент. 1. **Разделяемое** (**S**hared). Содержит свежие данные, могут быть копии. - Запись запрещена, требуется `L` $\rightarrow$ Exclusive, $\forall$ `C` $\rightarrow$ `Invalid`. - `L` $\rightarrow$ `Invalid` в любой момент. 1. **Не актуальное** (**I**nvalid). Не содержит корректных данных. (`L` — кеш-линия, `C` — копия(-ии) кеш-линии в другом процессоре,
`M` — запись в памяти) ---- #### Обмен информацией о состоянии кеш-линий ##### Справочник (Directory) Общий справочник с информацией о разделяемых данных.
- Перед загрузкой записи осуществляется проверка через справочник. - При изменении каталог либо обновляет, либо аннулирует другие кеши с этой записью.

- Достоинство: масштабирование, количество процессоров может быть велико. - Недостаток: задержка запроса к справочнику. ---- ##### Отслеживание (Snooping)

Отслеживание операций других процессоров с памятью. - Кеши отслеживают **адресные линии** на предмет обращений к данным своих кеш-линий. - Если наблюдается запись — кеш помечает линию как "не актуальную".
- Достоинство: скорость. - Недостаток: ограниченная масштабируемость. ##### Перехват (Snarfing) - Кеши отслеживают **адресные линии** и **линии данных** на предмет обращений к данным своих кеш-линий. - Если наблюдается запись — кеш обновляет кеш-линию. ---- #### CAP-теорема. То же, но в большем масштабе
В распределённых системах нельзя одновременно обеспечить: 
1. **Согласованность** (Consistency) — каждое чтение получает последнюю запись или ошибку. 1. **Доступность** (Availability) — каждый запрос получает ответ (без ошибок), но и без гарантии, что он содержит последнюю запись. 1. **Устойчивость к разбиению** (Partition Tolerance/Brainsplit) — система продолжает работать, несмотря на произвольное количество потерь в сети между узлами.
--- ### Кеш. Непрозрачность 1. В теории, кеш-память прозрачна для программиста. Он не должен ожидать неприятностей от неё. 1. На практике: - Meltdown. - Кеш и недостатки спекулятивных вычислений
$\rightarrow$ утечка по стороннему каналу. - Смотрите в докладах по лаб. 1. - Кеш и перемножение матриц. - Array of Structures (AoS) vs. Structure of Arrays (SoA). [Экспериментальное определение характеристик кеш-памяти](https://habr.com/ru/post/148839/) ---- #### Перемножение матриц
$c_{ij} = \sum_{r=1}^m a_{ir}b_{rj} \left(i=1, 2, \ldots l ; \\; j=1, 2, \ldots n \right)$ где: - A ($l\times m$), B ($m \times n$) — исходные матрицы. - C — результирующая матрица. - Хранение матриц: `int**` (двумерный массив).

----
##### Наивное перемножение ```c for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { C[i][j] = 0; for (int k = 0; k < size; k++) { C[i][j] += A[i][k] * B[k][j]; } } } ``` ##### Транспонированное умножение ```c B2 = transpose(size, B); // ... for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { C[i][j] = 0; for (int k = 0; k < size; k++) { C[i][j] += A[i][k] * B2[j][k]; } } } ```
 
---- ##### Результаты эксперимента   ---- #### Array of Structures (AoS)
vs. Structure of Arrays (SoA)
```C struct point3D { float x; float y; float z; }; struct point3D points[N]; float get_point_x(int i) { return points[i].x; } ```
```C struct pointlist3D { float x[N]; float y[N]; float z[N]; }; struct pointlist3D points; float get_point_x(int i) { return points.x[i]; } ```
1. Эффективность работы кеша. 1. Поддержка адресации групповых операций с точки зрения ISA. 1. Колоночные базы данных. --- ### Виртуальная память и Кеш С какими адресами работает кеш, физическими или виртуальными? ---- ### Кеш-память с виртуальными адресами
#### Преимущества (ВА) - **Быстрота доступа**. Доступ к памяти минуя трансляцию адреса. - **Простота реализации**. Простота кеш памяти. Не требуется трансляция адресов перед проверкой кеш попадания.
#### Недостатки (ВА) - **Проблемы совместимости процессов**. Требуется различать контексты из-за коллизий виртуальных адресов. - **Неэффективность при смене контекста**. Смена контекста может потребовать очистку кеша для предотвращения конфликтов данных.
---- ### Кеш-память с физическими адресами
#### Преимущества (ФА) - **Универсальность**. Физические адреса уникальны в рамках системы. - **Консистентность данных**: Физические адреса упрощают поддержание консистентности кешей и памяти.
#### Недостатки (ФА) - **Задержки из-за трансляции адресов**: Доступ к данным в кеше по физическому адресу требует предварительной трансляции виртуального адреса. - **Сложность реализации**: Необходимость поддержки трансляции адресов увеличивает сложность управления кешем.
Возможны смешанные варианты: - `L1` — виртуальные адреса для минимизации задержек, - `L2`, `L3` — физические для универсальности и консистентности. --- ### Кеш. Доведём до абсурда, или нет? #### Типичный маршрут работы приложения  ---- #### Маршрут работы приложения, если память персистентна  ---- #### PhantomOS  1. Unix: "Всё есть файл" $\longrightarrow$ Фантом: "Всё есть объект". 1. Единое глобальное виртуальное пространство — доступ по ссылке. 1. Snapshots всей системы. 1. [Дмитрий Завалишин — ОС «Фантом» и Java: сборка мусора](https://www.youtube.com/watch?v=DHCrUADYlJc) — с техническими деталями. 1. [Smalltalk. Pharo](https://www.pharo.org): Объектный язык (никакой не "ориентированный"). IDE и OS — одно целое. Файлы не нужны (даже для кода).