Количество ядер, их архитектура и частота — три ключевые характеристики центрального процессора. Но не менее важную роль играет еще одна: кэш. Это быстрая память небольшого объема, расположенная на кристалле рядом с вычислительными ядрами. Для чего нужен кэш? Как он работает, на что влияет и как устроен внутри?
Немного истории: память в вычислительных системах
Компьютеры, ноутбуки, планшеты, смартфоны и даже миниатюрные смарт-часы — все эти устройства представляют собой разновидности вычислительных систем. В основе работы любой из них два ключевых компонента: подсистема памяти, в которой находятся данные для расчетов, и процессор, который эти расчеты производит.
На заре появления вычислительные системы состояли из простых пар «процессор — память». Сначала код полностью загружался в память с помощью тумблеров, штекерной панели или перфокарт, и лишь затем процессор начинал считывать его оттуда и выполнять команды. Результаты вычислений выводились либо на панель с индикаторами, либо с помощью «дедушек» современных принтеров — телетайпов, перфораторов или алфавитно-цифровых печатающих устройств.
В конце 70-х годов прошлого века место ранее используемых ртутных, механических и магнитных видов памяти окончательно заняла полупроводниковая. Перфокарты и перфоленты уступили место кассетам с магнитной лентой, а еще через несколько лет — флоппи-дискам. Тогда вычислительные системы наконец обрели близкий к современным формат работы: устройство постоянной памяти (накопитель) — оперативная память (ОЗУ) — процессор.
Типы оперативной и постоянной памяти с тех пор не раз менялись, но общий принцип работы вычислений оставался прежним. Упрощенно его можно представить так:
Программа загружается из постоянной памяти в оперативную.
Процессор считывает данные из оперативной памяти и выполняет над ними вычисления.
Результаты вычислений возвращаются в оперативную память.
Программа использует результаты для передачи на устройство вывода (экран/динамики/принтер), либо для записи обратно в постоянную память.
Частоты ЦП в то время росли не по дням, а по часам. Уже к середине 80-х процессоры стали работать заметно быстрее, чем микросхемы оперативной памяти. Из-за этого все чаще возникали ситуации, которые сегодня называют боттлнеком: во многих задачах ЦП приходилось ждать загрузки из ОЗУ и пропускать рабочие такты, теряя заметную часть производительности.
Решением этой проблемы стало внедрение кэша: очень быстрой памяти малого объема, служащей буфером данных между процессором и оперативкой. В x86-процессорах кэш впервые появился в 1987 году у модели Intel 80386, с тех пор став стандартным элементом практически любой вычислительной системы.
Как работает кэш
Про кэш часто говорят, что «это та же оперативная память, только в разы быстрее и намного меньше по объему». Отчасти это и правда так, ведь кэш выполняет работу, которая до его появления была исключительно делом ОЗУ — максимально быстро передавать процессору данные, необходимые для расчетов.
Однако на деле принципы работы кэша и оперативки заметно отличаются. ОЗУ заполняется только теми данными, которые запрашивают выполняемые программы. Контролирует этот процесс операционная система — то есть, в данном случае управление памятью полностью программное.
Если бы кэш-память можно было бы сделать размером с оперативную, то последняя оказалась не нужна бы вовсе. Но ОЗУ у современных систем исчисляется гигабайтами, а кэш — мегабайтами. Разница в объеме между ними составляет порядка тысячи раз, и подобное положение сохраняется уже четвертое десятилетие.
Но как же кэш при столь малом объеме помогает ЦП получать быстрый доступ к данным выполняемых программ? Дело в том, что такая память намного «умнее». Вместо того, чтобы загружать только используемую в данный момент информацию, кэш заполняется данными на основе:
Принципа временной локальности. Когда процессор делает запрос к определенному адресу в ОЗУ, то он с большой вероятностью будет обращаться к нему снова. Для таких случаев кэш продолжает сохранять ранее запрошенные данные.
Принципа пространственной локальности. Если процессор делает запрос к определенному байту памяти, то он наверняка будет обращаться и к информации в соседних байтах. Поэтому в кэш загружается не один запрашиваемый байт, а целая кэш-линия, обычно 64 байта.
Работы Prefetchers. Это аппаратные блоки предвыборки данных, занимающиеся поиском зависимостей в коде (Instruction Prefetchers) и данных (Data Prefetchers). Когда они «видят», что программа запрашивает информацию в определенной последовательности, то начинают загружать эту последовательность в кэш заранее — еще до того, как эти данные понадобятся процессору.
После того, как кэш заполнился, в дело вступают алгоритмы вытеснения данных. Они решают, какую информацию еще нужно держать в кэше, а какую можно удалить, освободив место для новой. За их работу отвечают:
Контроллер кэша. Хранит и сверяет теги, указывающие на соответствие данных в кэше адресам из ОЗУ.
Блок замещения. Следит за «возрастом» данных в строках кэша, чтобы при поступлении новой информации заменить ей самую старую.
Буфер обратной записи. Вступает в дело после блока замещения: сохраняет старую информацию до тех пор, пока она не будет записана в кэш уровнем ниже или оперативную память.
Агент когерентности. Когда одно ядро ЦП изменяет определенную информацию в ОЗУ, то кэши других ядер продолжают хранить ее старые версии. Этот блок отслеживает изменения в кэшах, помечая старые данные недействительными и организуя загрузку их актуальных версий.
Чтобы отслеживать устаревание данных одновременно во всем массиве кэша и при этом обеспечивать запись новой информации в любую его точку, требуется очень сложная логика. Для решения этой проблемы с конца 80-х годов и по сегодняшний день в процессорах используется множественно-ассоциативный кэш (Set-Associative Cache).
При таком подходе набор адресов оперативной памяти привязывается к нескольким ячейкам кэша (в современных ЦП — от 8 до 20). Когда поступает команда на запись из привязанного адреса, алгоритмы вытесняют информацию из одной ячейки набора, не затрагивая остальные. Это позволяет эффективно избавляться от старых данных, сохраняя актуальную информацию в кэше без необходимости постоянно «гонять» ее из ОЗУ.
За счет слаженной работы вышеописанных алгоритмов и блоков кэш способен предварительно загрузить в себя до 99 % данных, необходимых для расчетов. Это избавляет вычислительный конвейер процессора от простоя, вызванного ожиданием информации из оперативной памяти.
Вдобавок к аппаратным методам управления содержимым кэша существуют также программные. Если разработчик ПО видит, что его код при «самодеятельности» процессора не очень эффективно использует кэш или забивает его ненужными данными, он может использовать:
Команды предвыборки. «Советуют» процессору подтянуть выбранные данные из ОЗУ в кэш заранее.
Команды потоковой записи. Заставляют ЦП записывать данные напрямую в оперативную память, минуя кэш.
Команды обслуживания. Позволяют сбрасывать содержимое кэша частично или полностью.
Устройство иерархии кэшей
Единственный кэш пробыл у процессоров недолго. В 1989 году в Intel 80486 дебютировала система кэширования с двумя уровнями (L1 и L2). А четыре года спустя в Intel Pentium кэш первого уровня для более эффективной работы был поделен на две независимые части — для инструкций (L1 Instruction) и для данных (L1 Data).
С развитием многоядерности в 2007-2008 годах в ЦП появился кэш третьего уровня (L3). В отличие от прочих уровней, он стал общим хранилищем для всех процессорных ядер и помог им обмениваться данными друг с другом без помощи оперативной памяти. А последним появился кэш микроопераций (L0): им оснащены все Intel Сore (со второго поколения) и AMD Ryzen.
К сегодняшнему дню иерархия кэшей у современных процессоров приняла следующий вид:
Кэш L0. Хранит очередь микроопераций, декодированных ядром из инструкций.
Кэш L1I. Используется для инструкций, которым предстоит пройти декодирование.
Кэш L1D. Хранит данные: числа, указатели, логические значения.
Кэш L2. Общий уровень для данных и инструкций каждого ядра.
Кэш L3. Общий уровень для данных и инструкций всех ядер.
Чем выше уровень кэша, тем быстрее он работает. Но чем быстрее ячейки кэш-памяти, тем сложнее их разводка, выше энергопотребление и нагрев. Если сделать L1 размером с L3, то он будет потреблять огромное количество энергии и перегревать ядра даже в простых задачах. Поэтому система кэширования сочетает несколько уровней разного объема, задержка доступа к которым заметно различается. У современных ЦП это:
L0: без задержки или 1 такт, 4000-6000 микроопераций (на ядро),
L1 (I+D): 4-5 тактов, 64-112 кБ (на ядро),
L2: 8-16 тактов, 0.5-3 МБ (на ядро),
L3: 40-55 тактов, 12-192 МБ (общий для всех ядер).
В зависимости от архитектуры процессора, разные уровни могут иметь отличающуюся организацию кэш-памяти:
Инклюзивную. Кэш хранит в себе полную копию информации, которая есть в верхних уровнях. При таком подходе тратится меньше времени на поиск данных между ядрами, но из-за дубликатов не весь объем кэша используется эффективно.
Эксклюзивную. Данные могут находиться только на одном уровне кэша, что позволяет максимально эффективно использовать его объем. Но если одному ядру нужны данные, лежащие в кэше другого, то приходится обновлять информацию на всех уровнях иерархии — это вызывает дополнительную задержку.
Нестрого инклюзивную. Сочетает преимущества двух вышеописанных организаций. Здесь данные могут дублироваться на нижних уровнях кэша, но только в том случае, если так «решили» его алгоритмы работы.
Принцип работы кэша схож при любой организации: когда запускаются вычисления, процессор начинает искать нужную информацию в L0/L1. При неудаче («промах») отправляется запрос в L2, а если ее и там не нашлось — то в L3. В случае, когда нужных данных нет ни на одном уровне кэша, процессору приходится запрашивать их из оперативной памяти. С современной DDR4 и DDR5 такой запрос обходится потерей от 250 до 450 тактов: это в 5-10 раз больше, чем доступ к самому «медленному» L3.
Технологии расширения кэш-памяти
На заре появления микросхемы кэша располагались либо на материнской плате, либо в картридже процессора. Но к 2000 году и Intel, и AMD интегрировали оба уровня кэш-памяти внутрь кристаллов своих ЦП, наконец избавив кэш от роли внешнего элемента.
С тех пор объемы кэшей понемногу росли. Однако главным препятствием к их резкому увеличению все также оставалась сложность SRAM-памяти, требующей много транзисторного бюджета. Создавать процессор, где более половины кристалла занял бы кэш, в 2000-е годы было трудно. Но даже когда такая возможность появилась, проектировать нишевый чип никто не хотел, ведь вместо огромного кэша на той же площади можно было разместить больше вычислительных ядер.
Для решения данной задачи проще всего было вернуться к корням кэша: многочиповой компоновке. Впервые на это в 2013 году решилась компания Intel. Тогда она оснастила свои мобильные Core четвертого поколения дополнительным кристаллом eDRAM объемом 128 МБ. Он работал заметно медленнее L3 и поэтому играл роль общего кэша следующего, четвертого уровня (L4).
Благодаря огромному объему чип eDRAM позволял процессорам тех лет практически не обращаться в ОЗУ напрямую, за счет чего их конвейер не простаивал даже в самых сложных ситуациях. Но память eDRAM была дорога, поэтому так и не стала массовой: в топовых мобильных Intel она изредка встречалась вплоть до восьмого поколения Core, а в десктопе и вовсе появилась только в двух моделях пятого поколения.
В 2022 году схожую идею впервые реализовала компания AMD. Но она выбрала другой путь: вместо добавления относительно медленного чипа L4 «приклеивать» поверх процессорного чиплета быстрый кристалл c дополнительным объемом L3. Эта технология получила название 3D V-Cache.
Объем кэша: когда и почему становится решающим
В отличие от ОЗУ, кэш является высоко интегрированной памятью. Скорость и ассоциативность кэша подбираются на этапе проектирования процессорной архитектуры так, чтобы при ограниченном транзисторном бюджете максимально выгодно устранить ее «узкие» места. Поэтому сравнивать эти параметры напрямую у ЦП разных поколений не имеет смысла.
Гораздо более универсальная характеристика, на которую стоит обращать внимание при выборе ЦП — это общий объем кэша. Хотя из-за отличающейся компоновки процессоров Intel и AMD используют разные подходы к формированию его уровней («синие» — упор на объем L2, «красные» — упор на объем L3), правило «больше — значит лучше» работает здесь почти всегда.
Почему? Все просто: чем объемнее кэши, тем больше в них «влезает» различных данных, которые могут понадобиться ЦП в следующий момент времени. Поэтому процент ситуаций, когда нужная информация оказалась в кэше («попадание») с ростом его объема становится более высоким. За счет этого процессор реже обращается за данными к медленной ОЗУ и, как следствие, меньше теряет свою скорость.
Впрочем, производительность ЦП зависит от объема кэша далеко не всегда. Прирост от его увеличения заметен лишь тогда, когда выполняемый код хаотичен — в играх, 3D-моделировании или инженерном ПО. И чем больше кэш, тем выше он будет. Например, трехкратное увеличение объема кэша у процессоров AMD Ryzen X3D способно дать им в подобных задачах от 10 до 50 % дополнительной скорости.
Но с относительно линейным и предсказуемым кодом современные ЦП не получают от большого кэша заметного буста. К таким ситуациям относится работа с 2D-графикой, рендеринг, монтаж и кодирование видео — в них прирост от увеличения кэша колеблется от 0 до 5 %. Поэтому для подобных сценариев на объем кэша можно не обращать внимания: в них куда важнее архитектура процессора, его тактовая частота и количество ядер.
Сверхоперативная память процессора. Снижает потери времени на ожидание данных. Конвейер чаще работает и чем он быстрее, тем требовательнее к оперативной памяти. У актуального SRAM удельное быстродействие больше, чем у LPDDR5X, GDDR7 и даже HBM4. Обычный DRAM почти во всём значительно проигрывает.
Но его в сотни или тысячи раз больше. Пришлось пользоваться как посредником между кэшем и SSD или иной постоянной памятью. ПЗУ ещё медленнее, без системного ОЗУ простои будут слишком длительными и это ускорит их поломку. Больше ядер и частот - чаще обращается к кэшу. Больше кэша - меньше обращений к DDR.
Что до практики, много кэша позволяют частично забить на скорость обычной оперативной памяти и системных шин. Но SRAM дорогая, медленным CPU и GPU её добавляют по минимуму или нехватку компенсируют быстрым DRAM.
Обычно старшие APU самые требовательные до ОЗУ. С дискретной видеокартой проблема меньше выражена. И нельзя сравнивать разные архитектуры только по одному параметру. Смотрим комплексно, также долго тестируем большим набором задач.
Своими словами и подробнее, наглядно. Либо со смежными темами. Много кэша уместнее при непредсказуемом потоке вычислений. SRAM дорог и CPU с eDRAM, 3D V - cache или bLLC нужны немногим.
Не массовый продукт, для специфичных задач. Усреднённый оптимальный объём итак реализован в большинстве привычных моделей. Но если ажиотаж с DRAM продлится долго, то может появиться кэш L4. Особенно если DDR6 будет не так хороша, как ожидают.
L3 существовал в 2003 году. Pentium 4 EE сокета 478 на ядре Gallatin. Серверный кристалл Xeon с 2 мегабайтами кэша установили на настольный процессор. Но массовым кэш 3 уровня стал с 2007 года, начиная с линейки Phenom сокета АМ2+. Поначалу было мало и медленно, лучше сделали к 2010.
Упрощающее очеловечивание. SRAM это карлик - гигачад. DRAM это толпа депрессивных астеников. Суммарно последние перенесут намного больше вещей за раз. Но быстро устают, больше едят и каждое действие долгое. Первого уместнее поставить у станка, а не грузчиком назначить.