Процессор современного компьютера способен складывать два 64-битных числа за один такт, а на частоте 4 ГГц это занимает четверть наносекунды. Оперативная память на этом фоне выглядит неповоротливой: между запросом данных и их появлением на шине проходит десятки, а то и сотни тактов простоя. Чтобы вычислительное ядро не тратило время впустую в ожидании байтов из ОЗУ, инженеры выстроили внутри процессора собственную иерархию сверхбыстрой памяти из трех уровней, и понимание того, как она устроена, объясняет, почему один процессор с меньшей частотой иногда обгоняет другой с более высокой.

Почему обычной оперативной памяти не хватает для скорости современных ядер

Ядро процессора и модули ОЗУ живут в разном темпе. DDR-память работает на частоте в сотни мегагерц и требует времени на активацию нужной строки, выбор столбца и передачу данных на шину: суммарная задержка складывается из параметров tRCD и tCL, а в тактах ядра это превращается в внушительное число простоя, порой достигающее двух-трех сотен тактов на один промах. Пока процессор ждет ответа от памяти, он мог бы выполнить сотни арифметических операций. Разница в скорости между ядром и ОЗУ называется в инженерной среде проблемой памяти: производительность вычислительных блоков растет быстрее, чем скорость доступа к оперативной памяти, и разрыв между ними со временем только увеличивается. Кэш-память стала практическим ответом на эту проблему: небольшой, но очень быстрый буфер данных располагается прямо рядом с ядром или внутри его собственного кристалла.

Как устроен самый близкий к ядру кэш первого уровня

L1 (Level 1) - это первая линия обороны между ядром и медленной памятью. Его размер обычно составляет от 16 до 64 килобайт на ядро, и он физически встроен в кристалл процессора буквально в нескольких микрометрах от исполнительных блоков. Из-за такой близости и применения самых современных производственных норм L1 обеспечивает минимальную задержку: попадание в кэш первого уровня в современных x86-ядрах обходится примерно в 4-5 тактов, что на частотах около 4-5 ГГц по-прежнему укладывается в районе одной наносекунды. Кэш L1 почти всегда разделен на два независимых блока: кэш данных (L1d) и кэш инструкций (L1i). Такое разделение позволяет ядру одновременно загружать команду для выполнения и данные, с которыми эта команда работает, вместо того чтобы гонять оба потока через одну и ту же шину. Именно из-за физической тесноты L1 остается самым маленьким кэшем в системе: увеличить его объем можно только ценой удлинения проводников и роста задержки, а это противоречит самому назначению L1 как самого быстрого звена цепи.

Отдельный параметр, который определяет и скорость, и гибкость кэша, - ассоциативность. В прямо отображаемом кэше каждому блоку оперативной памяти соответствует ровно одна строго определенная ячейка кэша, поэтому поиск получается максимально быстрым, но два разных блока памяти, которые случайно претендуют на одну и ту же ячейку, будут постоянно вытеснять друг друга. Полностью ассоциативный кэш решает эту проблему обратным способом: любой блок памяти может попасть в любую свободную ячейку, что снижает число конфликтов, но заметно усложняет и замедляет сам поиск, ведь контроллеру приходится сравнивать адрес сразу со всеми ячейками. Компромиссным и самым распространенным решением стал наборно-ассоциативный кэш, где вся память делится на несколько наборов по два, четыре, восемь или шестнадцать ячеек, а конкретный блок данных может занять любую свободную ячейку внутри своего набора. Именно такой подход используется в L1 большинства современных ядер: он дает почти такую же скорость, как прямое отображение, но заметно снижает число конфликтов и повторных промахов.

Что происходит внутри кэша второго уровня и почему он крупнее

Если нужных данных в L1 не оказалось, ядро обращается к L2. Этот уровень физически отделен от самых горячих участков ядра, поэтому инженеры позволяют себе делать его заметно просторнее: типичный диапазон составляет от 256 килобайт до 2 мегабайт, а в отдельных архитектурах и больше. За больший объем приходится платить временем: в современных чипах вроде AMD Zen 4 или Intel Raptor Lake доступ к L2 занимает порядка 12-16 тактов, тогда как в более ранних и компактных архитектурах эта цифра могла составлять около 8-10 тактов. В части современных ядер L2 объединяет данные и инструкции в единый унифицированный кэш и одновременно обслуживает второй уровень буфера ассоциативной трансляции адресов, который отвечает за перевод виртуальных адресов памяти в физические. У части чипов L2 закреплен строго за одним ядром, у других один блок L2 обслуживает сразу пару соседних ядер, деля между ними доступную емкость.

Как кэш третьего уровня превращает отдельные ядра в единую систему

L3 стоит особняком: в отличие от L1 и L2 он не привязан к конкретному ядру, а служит общим ресурсом для всего процессора. Через него ядра обмениваются данными между собой и хранят информацию, которая важна для чипа в целом, но запрашивается не так часто, как содержимое L1 или L2. Плата за общий доступ и физическую удаленность от ядер - самая высокая задержка среди трех уровней: в современных чипах обращение к L3 обычно занимает порядка 40-60 тактов, а при обмене данными между разными чиплетами в многокристальных процессорах, как у AMD, задержка может доходить и до 70-80 тактов. Зато объем L3 может быть внушительным: у Intel Core i9-14900K он достигает 36 мегабайт, а у процессоров AMD Ryzen с технологией трехмерного кэша счет идет на сотни мегабайт. Такой разброс в размерах и скорости трех уровней не случаен: чем ближе память к ядру, тем она быстрее и тем сильнее ограничена в объеме, и наоборот, чем дальше от ядра, тем свободнее инженеры в выборе размера ценой роста задержки.

Раз несколько ядер одновременно держат копии одних и тех же данных в своих личных L1 и L2, процессору нужен способ следить, чтобы ни одно ядро не работало с устаревшей версией числа, пока соседнее ядро уже изменило оригинал. Для этого чипы используют протоколы когерентности кэша, самый известный из которых называется MESI по первым буквам четырех состояний каждой строки данных: измененное, монопольное, общее и недействительное. Когда одно ядро меняет значение в своей копии строки, протокол помечает все остальные копии этой строки в кэшах соседних ядер как недействительные, и при следующем обращении к этим данным соседнее ядро обязано заново запросить актуальную версию через общий L3, а не работать со старым значением из собственного L1. Эта постоянная синхронизация - одна из причин, почему L3 физически объединен и доступен всем ядрам сразу: именно через него проще всего согласовывать состояние памяти во всей многоядерной системе.

Что случается при промахе кэша и обращении к оперативной памяти

Каждое обращение ядра к данным проходит по цепочке проверок. Сначала процессор смотрит в L1: если данные там есть, это называется попаданием, и цикл на этом завершается с минимальной задержкой. Если данных нет, происходит промах, и запрос уходит в L2; при удачном исходе найденный блок копируется обратно в L1 по правилам политики кэширования, чтобы повторный запрос к тем же данным снова оказался быстрым. Не найдя данные и в L2, контроллер обращается к L3, и в случае успеха загружает найденные байты сразу в L2 и L1. Лишь когда все три уровня отвечают промахом, процессор идет напрямую в оперативную память, и это самый медленный из штатных сценариев: ядру приходится буквально простаивать сотни тактов, дожидаясь ответа от ОЗУ. Важная деталь в работе кэша заключается в том, что процессор запрашивает не единичный байт, а сразу целую кэш-линию, как правило размером 64 байта, потому что соседние ячейки памяти с высокой вероятностью понадобятся программе в ближайшее время. Этот принцип называется пространственной локальностью, и на нем строится значительная часть выигрыша от кэширования. Стоит отдельно уточнить: наполнением кэша управляет не операционная система, а аппаратный контроллер внутри самого процессора и встроенный механизм предвыборки данных, который заранее подгружает в кэш блоки, к которым программа, вероятно, обратится следующей, опираясь на шаблоны предыдущих обращений к памяти.

Как дополнительный объем кэша меняет реальную производительность в играх

Наглядный пример того, насколько объем кэша влияет на конечный результат, дала технология трехмерного вертикального кэша AMD. Компания начала укладывать дополнительный слой памяти L3 прямо поверх кристалла ядра, соединяя его сквозными вертикальными переходами. Первый процессор с такой технологией, Ryzen 7 5800X3D, получил 96 мегабайт L3 вместо стандартных 32 и в игровых сценариях показал прирост частоты кадров около 15 процентов по сравнению с обычным Ryzen 7 5800X, при этом его тактовая частота была даже немного ниже конкурента. Флагманский Ryzen 9 7950X3D довел общий объем L3 до 128 мегабайт и в ряде проектов продемонстрировал прирост производительности в несколько десятков процентов при той же или меньшей частоте ядра. Причина в том, что многие игры плохо предсказуемы по своей природе: физика объектов, поведение противников, генерация текстур и анимаций требуют постоянного обращения к разбросанным по памяти данным, и чем больше таких данных умещается в быстром кэше рядом с ядром, тем реже процессору приходится ждать медленный ответ от оперативной памяти. При этом эффект от дополнительного кэша заметен далеко не во всех задачах: программы, упирающиеся не в память, а в чистую вычислительную мощность ядра, от увеличения L3 почти ничего не выигрывают, поэтому итоговый прирост сильно зависит от конкретного приложения.

На что обратить внимание при оценке кэша конкретного процессора

При выборе процессора для повседневных задач полезно смотреть не только на объем каждого уровня кэша, но и на то, как он распределен между ядрами. Возьмем практический пример: если чип на частоте 4 ГГц исполняет 4 миллиарда тактов в секунду и на каждый промах L1 с переходом в оперативную память в среднем теряется около 200 тактов простоя, то при доле промахов всего в 2 процента от общего числа обращений к памяти суммарные потери могут доходить до нескольких процентов производительности ядра просто на ожидании данных. Инженеры описывают эту зависимость простой формулой среднего времени доступа к памяти: итоговое время равно времени попадания в кэш плюс произведение доли промахов на штраф за промах. Если время попадания в L1 принять за 4 такта, долю промахов L1 за 5 процентов, а штраф за уход в L2 за 14 тактов, среднее время доступа получается равным 4 плюс 0,05, умноженное на 14, то есть 4,7 такта вместо возможных 18 при постоянном обращении сразу к L2. Тот же расчет можно продолжить на следующий уровень: если из этих 5 процентов промахов L1 еще 20 процентов не находят данные и в L2, а штраф за поход в L3 составляет 50 тактов, к среднему времени добавляется еще 0,05, умноженное на 0,2 и на 50, то есть 0,5 такта, и итоговое среднее время доступа приближается к 5,2 такта. Отсюда видно, что даже небольшой процент промахов на каждом уровне ощутимо утяжеляет итоговую задержку, и именно поэтому инженеры так упорно борются за снижение доли промахов, а не только за наращивание сырого объема кэша. Именно поэтому производители продолжают наращивать эффективность иерархии кэшей быстрее, чем растет частота самих ядер: выигрыш от сокращения промахов зачастую заметнее, чем выигрыш от дополнительных сотен мегагерц. Для типичных офисных и бытовых задач размер L2 и L3 обычно не становится узким местом, тогда как для игр, работы с большими базами данных, видеомонтажа и научных расчетов объем и скорость кэша нередко решают исход сравнения двух процессоров сильнее, чем разница в заявленной тактовой частоте.

Прежде чем сравнивать два процессора только по мегагерцам, стоит свериться с несколькими практическими ориентирами:

  1. Суммарный объем L2 и L3 на один физический процессор, а не только цифра из рекламной характеристики верхнего уровня;
  2. Способ распределения L3 между чиплетами или ядрами, поскольку неравномерное распределение способно создавать заметную разницу в задержках между отдельными ядрами;
  3. Наличие дополнительного вертикально уложенного кэша у игровых и рабочих серий процессоров, если приоритет отдается требовательным к памяти сценариям;
  4. Реальные тесты в конкретных задачах, а не только табличные значения задержек и объемов, поскольку итоговый эффект от кэша сильно зависит от характера нагрузки.

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