В каких процессорах есть кэш l4
Одинаковые компы с одинаковыми характеристиками. А на первом проц с L2 кэшем 4 мб и 0 мб L3 кэшем, а на втором проц с L2 кэшем 1 мб и 8 мб L3 кэшем. И предположим, что в остальном процы будут одинаковы. Насколько фпс на втором компе будет больше, чем на первом?
Конечно же важен!! !
Процессоры всегда работали быстрее, чем память, причем со временем разрыв между этими скоростями все увеличивается. Чем медленнее память, тем больше процессору приходится ждать. В кэш памяти находятся машинные слова (можно их назвать данными) , которые чаще всего используются процессором. Если ему требуется какое-нибудь слово, то он сначала обращается к кэш памяти. Только если его там нет, он обращается к основной памяти. Существует принцип локализации, по которому в кэш вместе с требуемым в данный момент словом загружаются также и соседние с ним слова, т. к. велика вероятность того, что они в ближайшее время тоже понадобятся. У обыкновенных процессоров существует кэш память двух уровней. Кэш первого уровня (L1) обычно разделён пополам, половина выделена для данных, а другая половина под инструкции. Кэш второго уровня (L2) предназначается только для данных. Пропускная способность оперативной памяти конечно высока, но кэш память всегда работает в несколько раз быстрее. У старых процессоров (Pentium, K6 и др. ) плата с кэшем L2 находилась на материнской плате. Скорость работы кэша при этом была довольно низкой, но её хватало. У Athlon K7, P2 и первых P3 кэш был помещён на специальную плату и работал на 1/2, 1/3 или 2/3 скорости ядра. У последних процессоров, в целях увеличения быстродействия, кэш L2 интегрирован в ядро и работает на его полной частоте. Стандартным и достаточным на данный момент считается объём кэша L2 в 256Kb. Многие процессоры имеют 512Kb L2. В ряде случаев большой кэш весьма полезен. С одной стороны, чем больше кэш, тем лучше, но с другой стороны, при увеличении кэша увеличивается время доступа к нему.
Кэш центрального процессора разделён на несколько уровней. Для универсальных процессоров — до 3. Кэш-память уровня N+1 как правило больше по размеру и медленнее по скорости обращения и передаче данных, чем кэш-память уровня N.
Самой быстрой памятью является кэш первого уровня — L1-cache. По сути, она является неотъемлемой частью процессора, поскольку расположена на одном с ним кристалле и входит в состав функциональных блоков. Состоит из кэша команд и кэша данных. Некоторые процессоры без L1 кэша не могут функционировать. На других его можно отключить, но тогда значительно падает производительность процессора. L1 кэш работает на частоте процессора, и, в общем случае, обращение к нему может производиться каждый такт (зачастую является возможным выполнять даже несколько чтений/записей одновременно) . Латентность доступа обычно равна 2−4 тактам ядра. Объём обычно невелик — не более 128 Кбайт.
Вторым по быстродействию является L2-cache — кэш второго уровня. Обычно он расположен либо на кристалле, как и L1, либо в непосредственной близости от ядра, например, в процессорном картридже (только в слотовых процессорах) . В старых процессорах — набор микросхем на системной плате. Объём L2 кэша от 128 Кбайт до 1−12 Мбайт. В современных многоядерных процессорах кэш второго уровня, находясь на том же кристалле, является памятью раздельного пользования — при общем объёме кэша в 8 Мбайт на каждое ядро приходится по 2 Мбайта. Обычно латентность L2 кэша, расположенного на кристалле ядра, составляет от 8 до 20 тактов ядра. В отличие от L1 кэша, его отключение может не повлиять на производительность системы. Однако, в задачах, связанных с многочисленными обращениями к ограниченной области памяти, например, СУБД, производительность может упасть в десятки раз.
Кэш третьего уровня наименее быстродействующий и обычно расположен отдельно от ядра ЦП, но он может быть очень внушительного размера — более 32 Мбайт. L3 кэш медленнее предыдущих кэшей, но всё равно значительно быстрее, чем оперативная память. В многопроцессорных системах находится в общем пользовании.
1. FPS больше зависит от видяхи, от процессора будет сильно зависеть если всю графику переложить на него.
2. Использование кэша и других модулей процессора уже зависит от того как оптимизировали игру разработчики, в большинстве игр кэш не особо важен, многим достаточно процессоров типа Celeron, яркий пример 1-й X-Box.
3. Если смотреть в будущее то может быть что угодно, тем более что програмисты последнее время стали плохо оптимизировать код расчитывая на мощь современных процессоров.
Насколько фпс на втором компе будет больше, чем на первом? -
Нинасколько. В данном варианте (тоесть в играх) кеш проца практически ничего не изменит. Тоесть разница возможна гдето на 0,5%.
Кэш больше будет нужен там где используется много памяти. гиг так 16-32. И в рабочих задачах а не играх которые используют 3-4 гига.
считаю ответ пользователя Запорожец Сусанин достойным стоять на первом месте, так как наиболее краток и полон. а скопировать тонны текста может любой уж простите дурак. в ответы майла ходят за конкретным, кратким, основанным на собственном опыте мнении. поэтому запорожец молодец.
И толку от самого медленного Кеша? Кеш л1 самый быстрый в процессоре, у1600 и 2600 доходит до 115gb s а у i3 9100f в два раза больше! При том цена и3 меньше.
Разрыв между быстродействием процессоров в общем смысле и быстродействием основной памяти DRAM, также в общем смысле, был проблемой в последние 30 лет – в этот период разрыв начал по-настоящему расти. И стоит честно сказать, что инженеры, разрабатывавшие как оборудование, так и программы, создавшие иерархию кэшей и ПО, способное воспользоваться её преимуществами, поступили просто гениально. Это одна из труднейших в реализации архитектур, когда-либо задуманных человеком.
Однако теперь, когда мы находимся на пороге появления постоянно расширяющейся иерархии памяти, когда начинает появляться энергонезависимая память типа Optane 3D XPoint (вариант памяти с изменением фазового состояния) в формате DIMM и SSD, а также новые протоколы (CXL, OpenCAPI, CCIX, NVLink и Gen-Z), возникает вопрос: не пора ли добавить серверам кэш четвёртого уровня? Поскольку от комплекса CPU зависит работа такого количества устройств – некоторые из которых расположены ближе, другие же дальше – логично задуматься над тем, не нужен ли нам ещё один уровень кэша, маскирующий задержки этих других видов памяти и увеличивающий пропускную способность всей системы.
Чтобы представить открывающиеся возможности, мы покопались в своей собственной памяти, а заодно пообщались с разработчиками архитектуры чипов из IBM, Intel, AMD и Marvell, чтобы понять, что они думают об использовании кэша L4 в серверах. Кэш L4, конечно, не новое слово в быстродействии, однако он и не так уж часто встречается в системных архитектурах.
Однако прежде нам стоит пробежаться по истории вопроса.
Добавление кэша первого уровня к процессорам, у которых в то время было всего одно ядро, в 1980-х стало компромиссом, добавляющим задержки в подсистемы памяти, одновременно снижающим среднюю задержку запросов данных и инструкций процессорами. Кэши L1 изначально находились во внешней SRAM, находившейся на материнских платах и подключавшейся к комплексу CPU-память. Такой кэш L1 находился очень близко к процессору, как в смысле тактовой частоты, так и в смысле физического пространства на плате, и давал возможность повысить загрузку CPU. Потом эти кэши разделили, чтобы в одном блоке можно было хранить часто используемые данные, а во втором – популярные инструкции, и это немного увеличило быстродействие. В какой-то момент увеличения тактовой частоты процессоров и соответствующего разрыва в быстродействии CPU и DRAM, были добавлены более жирные, но и более медленные кэши L2 (зато более дешёвые в пересчёте на пропускную способность), опять-таки сначала находившиеся вне корпуса CPU, а потом интегрированные в него. А когда в CPU начали добавлять всё больше и больше ядер, а также всё больше контроллеров DRAM для их загрузки, к иерархии добавили ещё более крупные блоки кэшей L3.
По большей части такая система работала достаточно хорошо. В некоторых схемах CPU мы даже видим определённые практические правила, отражающие уровни иерархии кэшей, которые позволят нам прикинуть возможности, связанные с четвёртым уровнем.
Крис Джианос, инженер чипов и архитектор из Intel, руководившей разработкой многих прошлых поколений процессоров Xeon, объясняет это так: «С каждым уровнем кэша нам обычно нужно, чтобы они выросли достаточно сильно по сравнению с предыдущим уровнем, чтобы всё это имело смысл, поскольку чтобы достичь заметного прироста быстродействия системы, нужно достичь достаточно интересной частоты успешных обращений. Если вы „попадаете“ в кэшированные данные всего в нескольких процентах случаев, это будет сложно заметить. Всё остальное затормаживает ваше быстродействие, и этот прирост будет незаметным. Поэтому требуются относительно большие кэши, и когда речь идёт о более высоких уровнях, нужны реально огромные кэши. Сегодня L2 измеряются мегабайтами, L3 измеряются десятками или сотнями мегабайт. Так что понятно, что если вы начинаете думать о кэше L4, то речь пойдёт уже о сотнях мегабайт, если не о гигабайтах. А такой размер определённо приведёт к их высокой стоимости. Нужно, чтобы сложились определённые условия, чтобы этот вариант стал интересным, и дешёвым он определённо не будет».
Инженеры из компании AMD, с которыми мы беседовали, пожелали остаться неизвестными потому, что они не хотели создать впечатление, что компания собирается добавить кэш L4 в линейку процессоров Epyc – и, если быть точным, AMD ничего такого и не обещала. Однако компания всё же признаёт, что это следующий очевидный шаг для рассмотрения, и, точно так же, как Intel, считает, что все инженеры размышляют о реализации кэша L4. По сути, AMD говорит, что компромиссы, связанные с уровнями кэшей и задержками подробно изучены как в промышленности, так и в научных кругах, и что с каждым новым уровнем, который оказывается больше и медленнее предыдущего, возникает компромисс увеличения общего пути к DRAM. Об этом говорит и Джианос из Intel, рассказывая о необходимости поиска баланса между успешными запросами к КЭШу и его объёмом.
IBM, конечно, добавляла кэш L4 к некоторым своим чипсетам X86 в 2000-х, а в 2010-х добавила L4 к чипсетам NUMA (неравномерный доступ к памяти) на мейнфреймах System z11. У процессора z11 четыре ядра, 64 КБ L1 кэш для инструкций и 128 КБ L1 кэш для данных, плюс 1,5 МБ L2 кэш для каждого из ядер и 24 МБ L3 кэш общего доступа для всех ядер. У чипсета NUMA для z10 было два банка по 96 МБ L4 кэша, то есть, 192 МБ в сумме. Выпустив z12, IBM урезала размер кэша L1 до 98 КБ на ядро, однако увеличила L2 кэш до 2 МБ на ядро, разделив его при этом на две части, для инструкций и для данных, как в случае с L1. Также она удвоила размер кэша L3 до 48 МБ для шести ядер, а размер кэша L4 был увеличен до 384 МБ для пары чипов в чипсете. При смене поколений процессоров System z объёмы кэшей росли, и у процессоров z15, анонсированных в сентябре, пара кэшей L1 будет весить по 128 КБ, пара кэшей L2 – по 4 МБ, а общий кэш L3 будет для 12 ядер иметь объём 256 МБ. Объём кэша L4 в каждом отсеке мейнфрейма составляет 960 МБ, а его общий объём для всей системы, состоящей из пяти отсеков, равняется 4,68 ГБ.
Как мы уже указывали ранее, у процессоров Power8 и Power9 память буферизована, а IBM добавила 16 МБ L4 кэша к каждому буферу Centaur, что составляет 128 МБ L4 кэша на сокет для 32-х планок памяти. У самых дешёвых машин с Power9 нет буфера памяти, а, следовательно, и кэша L4. Архитекторы, разрабатывавшие схему Power10, были заняты разработкой схемы для Power11, и потому не смогли ответить на наши вопросы, но Уильям Старк, управлявший разработкой Power10, нашёл для нас немного времени, и заметил следующее:
«В целом мы пришли к выводу, что кэши последнего уровня большого размера полезны для увеличения быстродействия промышленных систем, — пояснил нам Старк по емейл. – Высокие задержки, связанные с энергонезависимой памятью, в частности, с памятью с изменением фазового состояния, порождают запрос на кэширование – возможно, на кэш типа L4 – в иерархии накопительной памяти».
Именно так мы и думали. И, кстати, мы не утверждаем, что кэш L4 обязательно будет находиться в непосредственной близости от буферизированной памяти будущего DDR5 DIMM. Возможно, его лучше расположить между PCI-Express и кэшем процессора L3, а ещё лучше, в буферах памяти и между PCI-Express и кэшем процессора L3. Возможно, его для этого придётся поместить наверху контроллера I/O и памяти в будущей серверной архитектуре, что немного напоминает технологию Foveros от Intel.
На это возможно взглянуть и с другой точки зрения – допустим, у IBM была возможность менять размеры кристалла, и инженеры решили добавить кэш L4 к шине System z NUMA или к чипу буферизации памяти Power8 и Power9 не ради его самого, а просто потому, что у них оставалась ещё возможность добавить транзисторов после того, как все необходимые функции были реализованы. Иногда нам кажется, что количество ядер в процессорах Intel X86 зависит от размера кэша L3, который они могут себе позволить. Иногда кажется, что Intel назначает максимальный размер кэша L3 на один кристалл, и после этого кристаллы Xeon трёх разных размеров просто изготавливают по этим спецификациям – в последних поколениях у них по 10, 18 или 28 ядер на техпроцессе в 14 нм.
Нет причин для того, чтобы делать кэш L4 исключительно на встроенной DRAM (как делает IBM со своими чипами) или на базе куда как более дорогой SRAM – об этом нам напоминает Рабин Сугумар, архитектор чипов из компаний Cray Research, Sun Microsystems, Oracle, Broadcom, Cavium и Marvell:
«Наши кэши L3 уже достаточно большие, — говорит Сугумар. – Так что L4 в интересующем вас случае нужно делать по другой технологии. Возможно, eDRAM или даже HBM или DRAM. В данном контексте интересным вариантом выглядит реализация кэша L4 на основе HBM, и этот кэш решает не столько проблему задержки, сколько пропускной способности. Поскольку ёмкость HBM ограничена, а пропускная способность велика, мы можем получить определённую прибавку к скорости – и в некоторых специальных случаях мы действительно видим значительное увеличение пропускной способности». Сугумар добавляет, что для довольно большого количества применений наблюдается относительно большое количество «промахов» кэша. Однако нужно подсчитать – будет ли добавление очередного уровня кэша стоить того.
Ещё один возможный вариант использования чего-то наподобие кэша L4, говорит Сугумар, это использовать локальную DRAM в качестве кэша. «У нас не ведётся никаких подобных исследований в лаборатории, но допустим, у нас на чипе есть интерфейс с высокой пропускной способностью, соединенный с общей распределённой памятью где-то на другом конце шлейфа, на расстоянии от 500 нс до 1 мкc. Тогда один из вариантов использования будет создать кэш, перемещающий эти данные из общей распределённой памяти в локальную DRAM. Можно представить работу конечного автомата, управляющего этой памятью, поэтому большую часть времени обращения будут идти к локальной DRAM, и вы сможете минимизировать количество обращений к общей распределённой DRAM».
Нам этот вариант кажется очень интересной разновидностью NUMA. Кстати, Сугумар работал над распределённой памятью для высокоскоростных параллельных систем в Sun Microsystems ещё до того, как появилась энергонезависимая память. И одна из проблем с этими различными вариантами иерархии памяти заключалась в том, что если одна из них потеряется из-за отказа сети или шины, то вся машина упадёт. «В системах с распределённой памятью приходится обрабатывать отказы сети более элегантно, и это порождает множество сложностей при проектировании».
Ещё один момент в том, что нам хочется, чтобы любой кэш высокого уровня, даже не L4, был реализован по максимуму при помощи железа и по минимуму при помощи софта. Ядрам операционок и другому ПО всегда нужно некоторое время, чтобы догнать железо, будь то добавление новых ядер, или кэшей L3 или L4, или адресуемой энергонезависимой памяти.
«В какой-то момент дополнительный уровень кэша станет неизбежностью, — говорит Джианос. – У нас появился первый уровень кэша, и в какой-то момент появился и второй. А потом мы, в конце концов, добавили третий. И когда-то у нас будет четвёртый. Вопрос только – когда и зачем. И мне кажется, что ваши наблюдения, касающиеся возможностей этого кэша, достаточно интересные. Но в Intel пока не решили, когда или зачем будут обнародовать такие вещи. Другие компании тоже изучают этот вопрос; было бы глупо не исследовать его. Рано или поздно это произойдёт, однако скоро это будет, или не очень – пока неясно».
Во всех центральных процессорах любого компьютера, будь то дешёвый ноутбук или сервер за миллионы долларов, есть устройство под названием «кэш». И с очень большой вероятностью он обладает несколькими уровнями.
Наверно, он важен, иначе зачем бы его устанавливать? Но что же делает кэш, и для чего ему разные уровни? И что означает «12-канальный ассоциативный кэш» (12-way set associative)?
Что такое кэш?
TL;DR: это небольшая, но очень быстрая память, расположенная в непосредственной близости от логических блоков центрального процессора.
Однако мы, разумеется, можем узнать о кэше гораздо больше…
Давайте начнём с воображаемой волшебной системы хранения: она бесконечно быстра, может одновременно обрабатывать бесконечное количество операций передачи данных и всегда обеспечивает надёжное и безопасное хранение данных. Конечно же, ничего подобного и близко не существует, однако если бы это было так, то структура процессора была бы гораздо проще.
Процессорам бы тогда требовались только логические блоки для сложения, умножения и т.п, а также система управления передачей данных, ведь наша теоретическая система хранения способна мгновенно передавать и получать все необходимые числа; ни одному из логических блоков не приходится простаивать в ожидании передачи данных.
Но, как мы знаем, такой волшебной технологии хранения не существует. Вместо неё у нас есть жёсткие диски или твердотельные накопители, и даже самые лучшие из них далеки от возможностей обработки, необходимых для современного процессора.
Великий Т'Фон хранения данных
Причина этого заключается в том, что современные процессоры невероятно быстры — им требуется всего один тактовый цикл для сложения двух 64-битных целочисленных значений; если процессор работает с частотой 4 ГГЦ, то это составляет всего 0,00000000025 секунды, или четверть наносекунды.
В то же время, вращающемуся жёсткому диску требуются тысячи наносекунд только для нахождения данных на дисках, не говоря уже об их передаче, а твердотельным накопителям — десятки или сотни наносекунд.
Очевидно, что такие приводы невозможно встроить внутрь процессоров, поэтому между ними будет присутствовать физическое разделение. Поэтому ещё добавляется время на перемещение данных, что усугубляет ситуацию.
Увы, но это Великий А'Туин хранения данных
Именно поэтому нам нужна ещё одна система хранения данных, расположенная между процессором и основным накопителем. Она должна быть быстрее накопителя, способна одновременно управлять множеством операций передачи данных и находиться намного ближе к процессору.
Ну, у нас уже есть такая система, и она называется ОЗУ (RAM); она присутствует в каждом компьютере и выполняет именно эту задачу.
Почти все такие хранилища имеют тип DRAM (dynamic random access memory); они способны передавать данные гораздо быстрее, чем любой накопитель.
Однако, несмотря на свою огромную скорость, DRAM не способна хранить такие объёмы данных.
Одни из самых крупных чипов памяти DDR4, разработанных Micron, хранят 32 Гбит, или 4 ГБ данных; самые крупные жёсткие диски хранят в 4 000 раз больше.
Итак, хоть мы и повысили скорость нашей сети данных, нам потребуются дополнительные системы (аппаратные и программные), чтобы разобраться, какие данные должны храниться в ограниченном объёме DRAM, готовые к обработке процессором.
DRAM могут изготавливаться в корпусе чипа (это называется встроенной (embedded) DRAM). Однако процессоры довольно малы, поэтому в них не удастся поместить много памяти.
10 МБ DRAM слева от графического процессора Xbox 360. Источник: CPU Grave Yard
Подавляющее большинство DRAM расположено в непосредственной близости от процессора, подключено к материнской плате и всегда является самым близким к процессору компонентом. Тем не менее, эта память всё равно недостаточно быстра…
DRAM требуется примерно 100 наносекунд для нахождения данных, но, по крайней мере, она способна передавать миллиарды битов в секунду. Похоже, нам нужна ещё одна ступень памяти, которую можно разместить между блоками процессора и DRAM.
На сцене появляется оставшаяся ступень: SRAM (static random access memory). DRAM использует микроскопические конденсаторы для хранения данных в виде электрического заряда, а SRAM для той же задачи применяет транзисторы, которые работают с той же скоростью, что и логические блоки процессора (примерно в 10 раз быстрее, чем DRAM).
Разумеется, у SRAM есть недостаток, и он опять-таки связан с пространством.
Память на основе транзисторов занимает гораздо больше места, чем DRAM: в том же размере, что чип DDR4 на 4 ГБ, можно получить меньше 100 МБ SRAM. Но поскольку она производится по тому же технологическому процессу, что и CPU, память SRAM можно встроить прямо внутрь процессора, максимально близко к логическим блокам.
С каждой дополнительной ступенью мы увеличивали скорость перемещаемых данных ценой хранимого объёма. Мы можем продолжить и добавлять новые ступени,, которые будут быстрее, но меньше.
И так мы добрались до более строгого определения понятия кэша: это набор блоков SRAM, расположенных внутри процессора; они обеспечивают максимальную занятость процессора благодаря передаче и сохранению данных с очень высокими скоростями. Вас устраивает такое определение? Отлично, потому что дальше всё будет намного сложнее!
Не только числа
Кэш повышает производительность, ускоряя передачу данных в логические блоки и храня поблизости копию часто используемых инструкций и данных. Хранящаяся в кэше информация разделена на две части: сами данные и место, где они изначально располагаются в системной памяти/накопителе — такой адрес называется тег кэша (cache tag).
Когда процессор выполняет операцию, которой нужно считать или записать данные из/в память, то он начинает с проверки тегов в кэше Level 1. Если нужные данные там есть (произошло кэш-попадание (cache hit)), то доступ к этим данным выполняется почти сразу же. Промах кэша (cache miss) возникает, если требуемый тег не найден на самом нижнем уровне кэша.
В кэше L1 создаётся новый тег, а за дело берётся остальная часть архитектуры процессора выполняющая поиск в других уровнях кэша (при необходимости вплоть до основного накопителя) данных для этого тега. Но чтобы освободить пространство в кэше L1 под этот новый тег, что-то обязательно нужно перебросить в L2.
Это приводит к почти постоянному перемешиванию данных, выполняемому всего за несколько тактовых циклов. Единственный способ добиться этого — создание сложной структуры вокруг SRAM для обработки управления данными. Иными словами, если бы ядро процессора состояло всего из одного ALU, то кэш L1 был бы гораздо проще, но поскольку их десятки (и многие из них жонглируют двумя потоками инструкций), то для перемещения данных кэшу требуется множество соединений.
Для изучения информации кэша в процессоре вашего компьютера можно использовать бесплатные программы, например CPU-Z. Но что означает вся эта информация? Важным элементом является метка set associative (множественно-ассоциативный) — она указывает на правила, применяемые для копирования блоков данных из системной памяти в кэш.
Представленная выше информация кэша относится к Intel Core i7-9700K. Каждый из его кэшей Level 1 разделён на 64 небольших блока, называемые sets, и каждый из этих блоков ещё разбит на строки кэша (cache lines) (размером 64 байта). «Set associative» означает, что блок данных из системы привязывается к строкам кэша в одном конкретном сете, и не может свободно привязываться к какому-то другому месту.
Инклюзивный кэш L1+L2, victim cache L3, политики write-back, есть даже ECC. Источник: Fritzchens Fritz
Ещё один аспект сложности кэша связан с тем, как хранятся данные между разными уровнями. Правила задаются в inclusion policy (политике инклюзивности). Например, процессоры Intel Core имеют полностью инклюзивные кэши L1+L3. Это означает, что одни данные в Level 1, например, могут присутствовать в Level 3. Может показаться, что это пустая трата ценного пространства кэша, однако преимущество заключается в том, что если процессор совершает промах при поиске тега в нижнем уровне, ему не потребуется обыскивать верхний уровень для нахождения данных.
В тех же самых процессорах кэш L2 неинклюзивен: все хранящиеся там данные не копируются ни на какой другой уровень. Это экономит место, но приводит к тому, что системе памяти чипа нужно искать ненайденный тег в L3 (который всегда намного больше). Victim caches (кэши-жертвы) имеют похожий принцип, но они используются для хранения информации, переносимой с более низких уровней. Например, процессоры AMD Zen 2 используют victim cache L3, который просто хранит данные из L2.
Существуют и другие политики для кэша, например, при которых данные записываются и в кэш, и основную системную память. Они называются политиками записи (write policies); большинство современных процессоров использует кэши write-back — это означает, что когда данные записываются на уровень кэшей, происходит задержка перед записью их копии в системную память. Чаще всего эта пауза длится в течение того времени, пока данные остаются в кэше — ОЗУ получает эту информацию только при «выталкивании» из кэша.
Графический процессор Nvidia GA100, имеющий 20 МБ кэша L1 и 40 МБ кэша L2
Для проектировщиков процессоров выбор объёма, типа и политики кэшей является вопросом уравновешивания стремления к повышению мощности процессора с увеличением его сложности и занимаемым чипом пространством. Если бы можно было создать 1000-канальные ассоциативные кэши Level 1 на 20 МБ такими, чтобы они при этом не занимали площадь Манхэттена (и не потребляли столько же энергии), то у нас у всех бы были компьютеры с такими чипами!
Самый нижний уровень кэшей в современных процессорах за последнее десятилетие практически не изменился. Однако кэш Level 3 продолжает расти в размерах. Если бы десять лет назад у вас было 999 долларов на Intel i7-980X, то вы могли бы получить кэш размером 12 МБ. Сегодня за половину этой суммы можно приобрести 64 МБ.
Подведём итог: кэш — это абсолютно необходимое и потрясающее устройство. Мы не рассматривали другие типы кэшей в CPU и GPU (например, буферы ассоциативной трансляции или кэши текстур), но поскольку все они имеют такую же простую структуру и расположение уровней, разобраться в них будет несложно.
Был ли у вас компьютер с кэшем L2 на материнской плате? Как насчёт слотовых Pentium II и Celeron (например, 300a) на дочерних платах? Помните свой первый процессор с общим L3?
На правах рекламы
Наша компания предлагает в аренду серверы с процессорами от Intel и AMD. В последнем случае — это эпичные серверы! VDS с AMD EPYC, частота ядра CPU до 3.4 GHz. Максимальная конфигурация — 128 ядер CPU, 512 ГБ RAM, 4000 ГБ NVMe.
Почти все разработчики знают, что кэш процессора — это такая маленькая, но быстрая память, в которой хранятся данные из недавно посещённых областей памяти — определение краткое и довольно точное. Тем не менее, знание «скучных» подробностей относительно механизмов работы кэша необходимо для понимания факторов влияющих на производительность кода.
Пример 1: доступ к памяти и производительность
Как вы думаете, насколько второй цикл быстрее первого?
int [] arr = new int [64 * 1024 * 1024];
Первый цикл умножает все значения массива на 3, второй цикл только каждое шестнадцатое значение. Второй цикл совершает только 6% работы первого цикла, но на современных машинах оба цикла выполняются примерно за равное время: 80 мс и 78 мс соответственно (на моей машине).
Разгадка проста — доступ к памяти. Скорость работы этих циклов в первую очередь определяется скоростью работы подсистемы памяти, а не скоростью целочисленного умножения. Как мы увидим в следующем примере, количество обращений к оперативной памяти одинаково и в первом и во втором случае.
Пример 2: влияние строк кэша
Копнём глубже — попробуем другие значения шага, не только 1 и 16:
Вот время работы этого цикла для различных значений шага K:
Обратите внимание, при значениях шага от 1 до 16 время работы практически не изменяется. Но при значениях больше 16, время работы уменьшается примерно вдвое каждый раз когда мы увеличиваем шаг в два раза. Это не означает, что цикл каким-то магическим образом начинает работать быстрее, просто количество итераций при этом так же уменьшается. Ключевой момент — одинаковое время работы при значениях шага от 1 до 16.
Причина этого в том, что современные процессоры осуществляют доступ к памяти не побайтно, а небольшими блоками, которые называют строками кэша. Обычно размер строки составляет 64 байта. Когда вы читаете какое-либо значение из памяти, в кэш попадает как минимум одна строка кэша. Последующий доступ к какому-либо значению из этой строки происходит очень быстро.
Из-за того, что 16 значений типа int занимают 64 байта, циклы с шагами от 1 до 16 обращаются к одинаковому количеству строк кэша, точнее говоря, ко всем строкам кэша массива. При шаге 32, обращение происходит к каждой второй строке, при шаге 64, к каждой четвёртой.
Понимание этого очень важно для некоторых способов оптимизации. От места расположения данных в памяти зависит число обращений к ней. Например, из-за невыровненных данных может потребоваться два обращения к оперативной памяти, вместо одного. Как мы выяснили выше, скорость работы при этом будет в два раза ниже.
Пример 3: размеры кэшей первого и второго уровня (L1 и L2)
Современные процессоры, как правило, имеют два или три уровня кэшей, обычно их называют L1, L2 и L3. Для того, чтобы узнать размеры кэшей различных уровней, можно воспользоваться утилитой CoreInfo или функцией Windows API GetLogicalProcessorInfo. Оба способа так же предоставляют информацию о размере строки кэша для каждого уровня.
На моей машине CoreInfo сообщает о кэшах данных L1 объёмом по 32 Кбайт, кэшах инструкций L1 объёмом по 32 Кбайт и кэшах данных L2 объёмом по 4 Мбайт. Каждое ядро имеет свои персональные кэши L1, кэши L2 общие для каждой пары ядер:
Проверим эту информацию экспериментально. Для этого, пройдёмся по нашему массиву инкрементируя каждое 16-ое значение — простой способ изменить данные в каждой строке кэша. При достижении конца, возвращаемся к началу. Проверим различные размеры массива, мы должны увидеть падение производительности когда массив перестаёт помещаться в кэши разных уровней.
int steps = 64 * 1024 * 1024; // количество итераций
int lengthMod = arr.Length - 1; // размер массива -- степень двойки
На моей машине заметны падения производительности после 32 Кбайт и 4 Мбайт — это и есть размеры кэшей L1 и L2.
Пример 4: параллелизм инструкций
Теперь давайте взглянем на кое-что другое. По вашему мнению, какой из этих двух циклов выполнится быстрее?
int steps = 256 * 1024 * 1024;
int [] a = new int [2];
// первый
for ( int i = 0; i
// второй
for ( int i = 0; i
Оказывается, второй цикл выполняется почти в два раза быстрее, по крайней мере, на всех протестированных мной машинах. Почему? Потому, что команды внутри циклов имеют разные зависимости по данным. Команды первого имеют следующую цепочку зависимостей:
Во втором цикле зависимости такие:
Функциональные части современных процессоров способны выполнять определённое число некоторых операций одновременно, как правило, не очень большое число. Например, возможен параллельный доступ к данным из кэша L1 по двум адресам, так же возможно одновременное выполнение двух простых арифметических команд. В первом цикле процессор не может задействовать эти возможности, но может во втором.
Пример 5: ассоциативность кэша
-
Кэш прямого отображения, данные каждой строки кэша в оперативной памяти хранятся только в одной заранее определённой ячейке кэша. Простейший способ вычисления отображения: индекс_строки_в_памяти % количество_ячеек_кэша. Две строки, отображённые на одну и ту же ячейку, не могут находится в кэше одновременно.
К примеру, на моей машине кэш L2 размером в 4 Мбайт является 16-входовым частично-ассоциативным кэшем. Вся оперативная память разделена на множества строк по младшим битам их индексов, строки из каждого множества соревнуются за одну группу из 16 ячеек кэша L2.
Так как кэш L2 имеет 65 536 ячеек (4 * 2 20 / 64) и каждая группа состоит из 16 ячеек, всего мы имеем 4 096 групп. Таким образом, младшие 12 битов индекса строки определяют к какой группе относится эта строка (2 12 = 4 096). В результате, строки с адресами кратными 262 144 (4 096 * 64) разделяют одну и ту же группу из 16-ти ячеек и соревнуются за место в ней.
Чтобы эффекты ассоциативности проявили себя, нам необходимо постоянно обращаться к большому количеству строк из одной группы, например, используя следующий код:
public static long UpdateEveryKthByte( byte [] arr, int K)
const int rep = 1024 * 1024; // количество итераций
Stopwatch sw = Stopwatch.StartNew();
int p = 0;
for ( int i = 0; i < rep; i++)
arr[p]++;
p += K; if (p >= arr.Length) p = 0;
>
Метод инкрементирует каждый K-ый элемент массива. По достижении конца, начинаем заново. После довольно большого количества итераций (2 20 ), останавливаемся. Я сделал прогоны для различных размеров массива и значений шага K. Результаты (синий — большое время работы, белый — маленькое):
Синим областям соответствуют те случаи, когда при постоянном изменении данных кэш не в состоянии вместить все требуемые данные одновременно. Яркий синий цвет говорит о времени работы порядка 80 мс, почти белый — 10 мс.
-
Почему появляются вертикальные линии? Вертикальные линии соответствуют значениям шага при которых осуществляется доступ к слишком большому числу строк (больше 16-ти) из одной группы. Для таких значений, 16-входовый кэш моей машины не может вместить все необходимые данные.
Некоторые из плохих значений шага — степени двойки: 256 и 512. Для примера рассмотрим шаг 512 и массив в 8 Мбайт. При этом шаге, в массиве имеются 32 участка (8 * 2 20 / 262 144), которые ведут борьбу друг с другом за ячейки в 512-ти группах кэша (262 144 / 512). Участка 32, а ячеек в кэше под каждую группу только 16, поэтому места на всех не хватает.
Другие значения шага, не являющиеся степенями двойки, просто невезучие, что вызывает большое количество обращений к одинаковым группам кэша, а так же приводит к появлению вертикальных синих линий на рисунке. На этом месте любителям теории чисел предлагается задуматься.
Даже если бы кэш был полностью ассоциативным, это не позволило бы сохранить в нём 8 Мбайт данных. Заметьте, что в уже рассмотренном примере с шагом 512 и размером массива 8 Мбайт, нам необходим только 1 Мбайт кэша, чтобы сохранить все нужные данные, но это невозможно сделать из-за недостаточной ассоциативности кэша.
Ассоциативность кэша — интересная штука, которая может проявить себя при определённых условиях. В отличие от остальных рассмотренных в этой статье проблем, она не является настолько серьёзной. Определённо, это не то, что требует постоянного внимания при написании программ.
Пример 6: ложное разделение кэша
На многоядерных машинах можно столкнуться с другой проблемой — согласование кэшей. Ядра процессора имеют частично или полностью раздельные кэши. На моей машине кэши L1 раздельны (как и обычно), так же имеются два кэша L2, общие для каждой пары ядер. Детали могут различаться, но в целом современные многоядерные процессоры имеют многоуровневые иерархические кэши. Причём самые быстрые, но и самые маленькие кэши, принадлежат индивидуальным ядрам.
Когда одно из ядер модифицирует значение в своём кэше, другие ядра больше не могут использовать старое значение. Значение в кэшах других ядер должно быть обновлено. Более того, должна быть обновлена полностью вся строка кэша, так как кэши оперируют данными на уровне строк.
Продемонстрируем эту проблему на следующем коде:
private static int [] s_counter = new int [1024];
private void UpdateCounter( int position)
for ( int j = 0; j < 100000000; j++)
s_counter[position] = s_counter[position] + 3;
>
>
Если на своей четырёхядерной машине я вызову этот метод с параметрами 0, 1, 2, 3 одновременно из четырёх потоков, то время работы составит 4.3 секунды. Но если я вызову метод с параметрами 16, 32, 48, 64, то время работы составит только 0.28 секунды.
Почему? В первом случае, все четыре значения, обрабатываемые потоками в каждый момент времени, с большой вероятностью попадают в одну строку кэша. Каждый раз когда одно ядро увеличивает очередное значение, оно помечает ячейки кэша, содержащие это значение в других ядрах, как невалидные. После этой операции, все остальные ядра должны будут закэшировать строку заново. Это делает механизм кэширования неработоспособным, убивая производительность.
Пример 7: сложность железа
Даже теперь, когда принципы работы кэшей для вас не секрет, железо по-прежнему будет преподносить вам сюрпризы. Процессоры отличаются друг от друга методами оптимизации, эвристиками и прочими тонкостями реализации.
Кэш L1 некоторых процессоров может осуществлять параллельный доступ к двум ячейкам, если они относятся к разным группам, но если они относятся к одной, только последовательно. Насколько мне известно, некоторые даже могут осуществлять параллельный доступ к разным четвертинкам одной ячейки.
Процессоры могут удивить вас хитрыми оптимизациями. Например, код из предыдущего примера про ложное разделение кэша не работает на моём домашнем компьютере так, как задумывалось — в простейших случаях процессор может оптимизировать работу и уменьшить негативные эффекты. Если код немного модифицировать, всё встаёт на свои места.
Вот другой пример странных причуд железа:
private static int A, B, C, D, E, F, G;
Если вместо подставить три разных варианта, можно получить следующие результаты:
Инкрементирование полей A, B, C, D занимает больше времени, чем инкрементирование полей A, C, E, G. Что ещё страннее, инкрементирование полей A и C занимает больше времени, чем полей A, C и E, G. Не знаю точно каковы причины этого, но возможно они связаны с банками памяти (да-да, с обычными трёхлитровыми сберегательными банками памяти, а не то, что вы подумали). Имеющих соображения на этот счёт, прошу высказываться в комментариях.
У меня на машине вышеописанного не наблюдается, тем не менее, иногда бывают аномально плохие результаты — скорее всего, планировщик задач вносит свои «коррективы».
Из этого примера можно вынести следующий урок: очень сложно полностью предсказать поведение железа. Да, можно предсказать многое, но необходимо постоянно подтверждать свои предсказания с помощью измерений и тестирования.
Заключение
Надеюсь, что всё рассмотренное помогло вам понять устройство кэшей процессоров. Теперь вы можете использовать полученные знания на практике для оптимизации своего кода.
Все современные многоядерные процессоры имеют как минимум трехуровневый кэш (см. Почему нам нужно несколько уровней кэш-памяти?).
L1 - самый быстрый и самый маленький, L2 имеет немного большую задержку, но больше, а L3 содержит данные, которые используются всеми ядрами процессора (и даже больше и медленнее). Все хорошо.
Попытка гуглить фразу "L4 Cache" не дает пустых результатов. По-видимому, некоторые процессоры содержат кэш-память L4 (по-видимому, Intel Broadwell i7-5775C имеет 128 МБ eDRAM, реализованную как кэш-память L4).
Кто-нибудь знает для чего нужен кеш L4? Я нигде не могу найти документацию относительно ее назначения и функции.
1 ответ 1
Кэш 4 уровня (кэш L4) - это способ связать кэш 3 уровня, к которому может обращаться ЦП, и кэш L4, к которому могут обращаться как ЦП, так и ГП.
Кэш-память 4-го уровня была представлена Intel начиная с микроархитектуры Haswell. Кэш 4 уровня использует встроенный DRAM (eDRAM) в том же пакете, что и встроенный графический процессор Intel. Этот кеш позволяет динамически распределять память между встроенным графическим процессором и процессором и служит в качестве кеша-жертвы для кэша L3 ЦП.
Это текущее представление eDRAM для процессоров Haswell и Broadwell. Здесь мы видим, что доступ к eDRAM осуществляется с помощью хранилища тегов L4, содержащихся в LLC каждого ядра, и в результате действует скорее как кэш-память жертвы для L3, а не как реализация динамической памяти с произвольным доступом. Любые инструкции или оборудование, для которых требуются данные из eDRAM, должны проходить через LLC и выполнять преобразование тега L4, ограничивая его потенциал (хотя и ускоряют определенные конкретные рабочие нагрузки благодаря двунаправленному интерфейсу 50 ГБ / с на канал).
В Skylake расположение eDRAM меняется:
Вместо того, чтобы действовать как псевдо-L4-кэш, eDRAM становится буфером DRAM и автоматически прозрачен для любого программного обеспечения (ЦП или IGP), которому требуется доступ к DRAM. В результате другое оборудование, которое обменивается данными через системный агент (например, устройства PCIe или данные из набора микросхем) и требует информацию в DRAM, не нуждается в навигации по кэш-памяти L3 на процессоре.
Далее в статье указывается, что:
В то время как цель eDRAM состоит в том, чтобы быть как можно более плавной, Intel разрешает некоторый уровень управления на уровне драйверов, позволяя текстурам больше L3 находиться только в eDRAM, чтобы предотвратить перезапись данных, содержащихся в L3, и необходимость перепишите это для других рабочих нагрузок.
Кэш: многоуровневая парковка
На приведённом выше изображении процессор (CPU) обозначен прямоугольником с пунктирной границей. Слева расположены ALU (arithmetic logic units, арифметико-логические устройства); это структуры, выполняющие математические операции. Хотя строго говоря, они не являются кэшем, ближайший к ALU уровень памяти — это регистры (они упорядочены в регистровый файл).
Каждый из них хранит одно число, например, 64-битное целое число; само значение может быть элементом каких-нибудь данных, кодом определённой инструкции или адресом памяти каких-то других данных.
Регистровый файл в десктопных процессорах довольно мал, например, в каждом из ядер Intel Core i9-9900K есть по два банка таких файлов, а тот, который предназначен для целых чисел, содержит всего 180 64-битных целых чисел. Другой регистровый файл для векторов (небольших массивов чисел) содержит 168 256-битных элементов. То есть общий регистровый файл каждого ядра чуть меньше 7 КБ. Для сравнения: регистровый файл потоковых мультипроцессоров (так в GPU называются аналоги ядер CPU) Nvidia GeForce RTX 2080 Ti имеет размер 256 КБ.
Регистры, как и кэш, являются SRAM, но их скорость не превышает скорость обслуживаемых ими ALU; они передают данные за один тактовый цикл. Но они не предназначены для хранения больших объёмов данных (только одного элемента), поэтому рядом с ними всегда есть более крупные блоки памяти: это кэш первого уровня (Level 1).
Одно ядро процессора Intel Skylake. Источник: Wikichip
На изображении выше представлен увеличенный снимок одного из ядер десктопного процессора Intel Skylake.
ALU и регистровые файлы расположены слева и обведены зелёной рамкой. В верхней части фотографии белым обозначен кэш данных первого уровня (Level 1 Data cache). Он не содержит много информации, всего 32 КБ, но как и регистры, он расположен очень близко к логическим блокам и работает на одной скорости с ними.
Ещё одним белым прямоугольником справа показан кэш инструкций первого уровня (Level 1 Instruction cache), тоже имеющий размер 32 КБ. Как понятно из названия, в нём хранятся различные команды, готовые к разбиению на более мелкие микрооперации (обычно обозначаемые μops), которые должны выполнять ALU. Для них тоже существует кэш, который можно классифицировать как Level 0, потому что он меньше (содержит всего 1 500 операций) и ближе, чем кэши L1.
Вы можете задаться вопросом: почему эти блоки SRAM настолько малы? Почему они не имеют размер в мегабайт? Вместе кэши данных и инструкций занимают почти такую же площадь на чипе, что основные логические блоки, поэтому их увеличение приведёт к повышению общей площади кристалла.
Но основная причина их размера в несколько килобайт заключается в том, что при увеличении ёмкости памяти повышается время, необходимое для поиска и получения данных. Кэшу L1 нужно быть очень быстрым, поэтому необходимо достичь компромисса между размером и скоростью — в лучшем случае для получения данных из этого кэша требуется около 5 тактовых циклов (для значений с плавающей запятой больше).
Кэш L2 процессора Skylake: 256 КБ SRAM
Но если бы это был единственный кэш внутри процессора, то его производительность наткнулась бы на неожиданное препятствие. Именно поэтому в ядра встраивается еще один уровень памяти: кэш Level 2. Это обобщённый блок хранения, содержащий инструкции и данные.
Он всегда больше, чем Level 1: в процессорах AMD Zen 2 он занимает до 512 КБ, чтобы кэши нижнего уровня обеспечивались достаточным объёмом данных. Однако большой размер требует жертв — для поиска и передачи данных из этого кэша требуется примерно в два раза больше времени по сравнению с Level 1.
Во времена первого Intel Pentium кэш Level 2 был отдельным чипом, или устанавливаемым на отдельной небольшой плате (как ОЗУ DIMM), или встроенным в основную материнскую плату. Постепенно он перебрался в корпус самого процессора, и, наконец, полностью интегрировался в кристалл чипа; это произошло в эпоху таких процессоров, как Pentium III и AMD K6-III.
За этим достижением вскоре последовал ещё один уровень кэша, необходимый для поддержки более низких уровней, и появился он как раз вовремя — в эпоху расцвета многоядерных чипов.
Чип Intel Kaby Lake. Источник: Wikichip
На этом изображении чипа Intel Kaby Lake в левой части показаны четыре ядра (интегрированный GPU занимает почти половину кристалла и находится справа). Каждое ядро имеет свой «личный» набор кэшей Level 1 и 2 (выделены белыми и жёлтым прямоугольниками), но у них также есть и третий комплект блоков SRAM.
Кэш третьего уровня (Level 3), хоть и расположен непосредственно рядом с одним ядром, является полностью общим для всех остальных — каждое ядро свободно может получать доступ к содержимому кэша L3 другого ядра. Он намного больше (от 2 до 32 МБ), но и намного медленнее, в среднем более 30 циклов, особенно когда ядру нужно использовать данные, находящиеся в блоке кэша, расположенного на большом расстоянии.
Ниже показано одно ядро архитектуры AMD Zen 2: кэши Level 1 данных и инструкций по 32 КБ (в белых прямоугольниках), кэш Level 2 на 512 КБ (в жёлтых прямоугольниках) и огромный блок кэша L3 на 4 МБ (в красном прямоугольнике).
Увеличенный снимок одного ядра процессора AMD Zen 2. Источник: Fritzchens Fritz
Но постойте: как 32 КБ могут занимать больше физического пространства чем 512 КБ? Если Level 1 хранит так мало данных, почему он непропорционально велик по сравнению с кэшами L2 и L3?
Читайте также: