Многоуровневое кэширование

Специфика конструирования современных процессорных ядер привела к тому, что систему кэширования в подавляющем большинстве CPU приходится делать многоуровневой. Самой быстрой является кэш-память первого уровня - L1. Она является неотъемлемой частью процессора и работает на той же частоте, что и процессор. Кэш первого уровня (самый «близкий» к ядру) традиционно разделяется на две (как правило, равные) половины: кэш инструкций (L1I) и кэш данных (L1D). Это разделение предусматривается так называемой «гарвардской архитектурой» процессора, которая по состоянию на сегодня является самой популярной теоретической разработкой для построения современных CPU. В L1I, соответственно, аккумулируются только команды (с ним работает декодер, см. ниже), а в L1D — только данные (они впоследствии, как правило, попадают во внутренние регистры процессора). Следующим по быстродействию является кэш второго уровня - L2. Сначала он располагался на системной плате, но, начиная с процессоров Pentium III и Athlon, стал частью микросхемы процессора и может работать как на половинной, так и на полной частоте процессора. L2 кэш как правило, больше по объёму, и является уже «смешанным» — там располагаются и команды, и данные. L3 (кэш третьего уровня), как правило, полностью повторяет структуру L2, и в современных x86 CPU встречается редко. Чаще всего, L3 — это плод компромисса: за счёт использование более медленной и узкой шины, его можно сделать очень большим, но при этом скорость L3 всё равно остаётся более высокой, чем скорость памяти (хотя и не такой высокой, как у L2-кэша). Тем не менее, алгоритм работы с многоуровневым кэшем в общих чертах не отличается от алгоритма работы с одноуровневым, просто добавляются лишние итерации: сначала информация ищется в L1, если её там нет — в L2, потом — в L3, и уже потом, если ни на одном уровне кэша она не найдена — идёт обращение к основной памяти (ОЗУ).

Посмотрим, как работает эта иерархия: когда процессор обращается к памяти, считанное значение заносится в кэши всех уровней, так происходит всегда, новое значение в соответствии с некоторым алгоритмом замещает какую-то строку и в L1 и в L2. Если процессор в течение некоторого времени не будет обращаться к этим данным, очень вероятно, что они будут замещены другой строкой в L1, но поскольку размер L2 больше чем L1, данные сохраняются некоторое время в L2, до тех пор, пока не будут замещены и там. Если вдруг процессору понадобятся данные, которые были выгружены из L1, есть вероятность что данные есть в L2, обращение к которому хоть и дольше по времени чем к L1, но все же намного быстрее чем обращение к основной памяти. Из этих рассуждений понятно, почему размеры кэш-памяти должны расти с увеличением n в Ln, иначе теряется смысл в использовании дополнительного уровня – выгруженные из L1 данные имеют нулевые шансы сохраниться в L2.

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

Когда процессор первый раз обращается к ячейке памяти, ее содержимое параллельно копируется в кэш, и в случае повторного обращения в скором времени может быть с гораздо большей скоростью выбрано из кэша. При записи в память значение попадает в кэш, и либо одновременно копируется в память (схема Write Through - прямая или сквозная запись), либо копируется через некоторое время (схема Write Back - отложенная или обратная запись). При обратной записи, называемой также буферизованной сквозной записью, значение копируется в память в первом же свободном такте, а при отложенной (Delayed Write) - когда для помещения в кэш нового значения не оказывается свободной области; при этом в память вытесняются наименее используемая область кэша. Вторая схема более эффективна, но и более сложна за счет необходимости поддержания соответствия содержимого кэша и основной памяти.

Работа кэша.

Рассмотрим работу наборно-ассоциативного кэша, так как именно он применяется сегодня наиболее широко.

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

Физический адрес разбивается на 3 (в общем случае) составляющие. Offset зависит от размера строки кэша и используется для индексации нужного байта в строке, например, если в строке вмещается 32 байта, то размер поля offset 5 битов. Поле Index зависит уже от размера страницы кэш-памяти. Это поле служит индексом набора строк кэша (в процессорах AMD набор (set) называется банком (bank)).

Физический адрес:

TAG

INDEX

OFFSET

При обращении к кэшу, процессор с помощью поля index, находит нужную строку, далее,

тег записанный в кэше, и тег из адреса сравниваются для всех элементов набора, если совпадение обнаружено и флаг строки отличен от «Invalid» фиксируется кэш-попадание и данные выбираются из кэша без обращения в память.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: