Лекция № 7: Кэш процессора
Страницы: 1 2
Кэш с прямым отображением адресов
Несмотря на то, что полностью ассоциативный кэш обладает самыми лучшими свойствами, он редко используется на практике из-за больших накладных расходов при аппаратной реализации. Поэтому рассмотрим наболее простой вариант: кэш с прямым отображением адресов. В таком кэше каждый байт оперативной памяти может попасть только в одно место кэш-памяти.
Как и раньше, разделим кэш на стро́ки, и в каждой строке кэша будем хранить несколько (например, 16) байт оперативной памяти. Кроме того, предположим, что кэш имеет 65536 строк (таким образом, объём кэш-памяти равен 16×65536 = 1 Мегабайт).
Чтобы определить, в какое место кэш-памяти попадёт заданный байт из оперативной памяти, разделим адрес этого байта на несколько частей. Предположим, что адрес памяти состоит из 32-х бит:

Рисунок 1. Разделение адреса на части
То есть, грубо говоря, старшие биты адреса отбрасываются, а младшие однозначно описывают место в кэш-памяти, в которое будет записан заданный байт оперативной памяти. Старшие биты (тег) дают нам «номер мегабайта» оперативной памяти, а младшие — смещение внутри этого мегабайта. Поэтому каждый мегабайт оперативной памяти отобразится в кэш (рисунок 2). Тег хранится в строке кэш-памяти для того, чтобы определить, из какого именно мегабайта пришла эта строка.

Рисунок 2. Прямое отображение адресов
(на примере кэш-памяти объёмом 1 МБ)
Так как каждый байт оперативной памяти может находиться только в одном месте кэш-памяти, при записи новых данных в кэш нет необходимости решать, какие данные будут из кэша вытеснены: вытеснять нужно ту́ строку, на место которой приходит новый байт. Поэтому нет необходимости хранить «возраст» строки́ кэша.
Кроме того, нет необходимости иметь устройство сравнения тэга в каждой строке кэш-памяти. В полностью ассоциативном кэше эти устройства требовались, чтобы произвести сравнение тэгов одновременно во всех строках кэша. В кэше с прямым отображением мы будем искать наши данные лишь в одной конкретной строке, номер которой определяется адресом байта. Поэтому достаточно иметь лишь одно устройство сравнения в контроллере кэш-памяти.
В связи со сказанным строка кэш-памяти может быть устроена так, как показано на рисунке 3. Мы видим, что кэш с прямым отображением адресов устроен гораздо проще, чем полностью ассоциативный кэш (см. рисунок 6 из первой части лекции).

Рисунок 3. Строка кэша с прямым отображением адресов
Когда процессор выдаёт запрос на чтение байта оперативной памяти, кэш-контроллер выполняет следующие действия:
- разбивает адрес требуемого байта на части (как показано на рисунке 1), определяя тэг, номер строки́ кэша, и смещение в строке;
- сверяет тэг, записанный в нужной строке кэша, с тэгом, выделенным из адреса;
- если тэги не совпали (данные в кэше отсутствуют), то выполняются следующие действия:
- если бит модификации строки́ не равен нулю, то он обнуляется, и содержимое строки́ записывается в место оперативной памяти, определяемое хранящимся в строке тэгом и номером этой строки́ в кэше;
- в строку кэша из оперативной памяти загружаются 16 байт, среди которых находится требуемый процессором байт памяти (адрес этой последовательности байт равен адресу требуемого байта, но с обнулёнными последними четырьмя битами);
- тэг строки́ заменяется на тэг, выделенный из адреса требуемого байта;
- теперь требуемые данные точно присутствуют в кэше, и контроллер выдаёт байт процессору из строки́ кэша в соответствии со смещением, выделенным из адреса.
Когда процессор выдаёт запрос на запись байта в оперативную память, кэш-контроллер выполняет следующие действия:
- разбивает адрес требуемого байта на части (как показано на рисунке 1), определяя тэг, номер строки́ кэша, и смещение в строке;
- сверяет тэг, записанный в нужной строке кэша, с тэгом, выделенным из адреса;
- если тэги не совпали (перезаписываемые данные не прокэшированы), то выполняются следующие действия:
- если бит модификации строки́ не равен нулю, то содержимое строки́ записывается в место оперативной памяти, определяемое хранящимся в строке тэгом и номером этой строки́ в кэше;
- в строку кэша из оперативной памяти загружаются 16 байт, среди которых находится перезаписываемый процессором байт памяти (адрес этой последовательности байт равен адресу требуемого байта, но с обнулёнными последними четырьмя битами);
- тэг строки́ заменяется на тэг, выделенный из адреса требуемого байта;
- теперь перезаписываемые данные точно присутствуют в кэше, и контроллер модифицирует байт строки́ кэша в соответствии со смещением, выделенным из адреса;
- бит модификации строки́ устанавливается в 1.
Кэш с прямым отображением адресов является частным случаем полностью ассоциативного кэша, если стратегию вытеснения данных заменить с «вытеснения самой старой строки́» на «вытеснение строки́, имеющей то же самое смещение в своём мегабайте данных, что и требуемая/записываемая строка». Иногда это приводит к ситуациям, при которых кэш вообще не работает. Например, представим, что мы складываем соответствующие элементы двух массивов A и B, и так оказалось, что расстояние между этими элементами кратно размеру кэша. Тогда при поочерёдном обращении к элементам массивов A и B, они будут вытеснять друг друга из кэша, так как отображаются в одно и то же место кэш-памяти.
Из-за примитивной «стратегии замещения» кэш с прямым отображением адресов в среднем проигрывает по скорости полностью ассоциативному кэшу того же объёма, вытесняющему самую старую строку. Для того, чтобы сравнять скорости, объём кэша с прямым отображением должен быть увеличен в 4–8 раз.
Кэш с прямым отображением адресов, будучи самым простым с точки зрения аппаратной реализации, исторически был первым распространённым видом кэшей. Однако из-за своей низкой эффективности он был быстро вытеснен гораздо более совершенным N-ассоциативным кэшом.
N-ассоциативный кэш
Эта архитектура кэш-памяти сочетает в себе низкие накладные расходы при аппаратной реализации (почти как у кэша с прямым отображением адресов) и высокое быстродействие (почти как у полностью ассоциативного кэша).
В N-ассоциативном кэше каждый байт оперативной памяти может храниться не в одном месте кэш-памяти (как в кэше с прямым отображением адресов), и не во всех строках кэша (как в полностью ассоциативном кэше), а в N различных строках кэша, где N является степенью двойки.
Пусть, как и раньше, адрес состоит из 4-х байт, объём кэша равен одному мегабайту, длина строки́ — 16 байт. Для определённости рассмотрим пример работы четырёх-ассоциативного кэша.
Когда процессор производит обращение к оперативной памяти, адрес разделяется на компоненты, как показано на рисунке:

Рисунок 4. Разделение адреса на части в четырёх-ассоциативном кэше
Отличие от кэша с прямым отображением здесь в том, что контроллер кэш-памяти вправе выбирать два старших бита номера строки́ (hint) по своему усмотрению, тем самым записывая данные из оперативной памяти в одно из четырёх возможных для данного адреса мест кэш-памяти. В общем случае число бит в поле hint равно
.
Важно понимать, что сначала адрес разбивается на компоненты (тег, номер строки́, смещение), а затем производится выбор двух старших битов но́мера строки́. Таким образом, тег содержит неизменённые старшие биты адреса, тем самым позволяя определять, какие же на самом деле данные находятся в данной строке. Например, в строку кэш-памяти №1 (стро́ки нумеруются с нуля) могут попасть байты
из оперативной памяти, где N — любое число. При этом тэг как раз и хранит это N.
Но как выбрать эти два произвольных бита? Самое лучшее, что можно сделать — это заместить ту́ строку (из четырёх возможных), к которой наиболее долго не было обращений. Это опять приводит нас к необходимости хранить «возраст» каждой строки́ кэша. Однако в данном случае возраст может быть реализован гораздо проще, чем в полностью ассоциативном кэше. Посмотрим, как это можно сделать.
Мысленно разобьём кэш-память на непересекающиеся подмножества из четырёх строк таким образом, чтобы номера строк каждого подмножества имели одинаковые младшие биты, но отличались двумя старшими битами. Например, в первое подмножество войдут стро́ки номер 0, 16384, 32768 и 49152; во второе подмножество войдут стро́ки с номерами 1, 16385, 32769, 49153 и так далее.
Когда строка данных должна быть записана из оперативной памяти в кэш, однозначно определено подмножество строк, в которое она попадает, а конкретный элемент подмножества должен быть выбран контроллером. В этом случае 4 строки́ подмножества «соревнуются» друг с другом за вытеснение, причём стро́ки одного подмножества никогда не могут соревноваться со строками другого подмножества. Поэтому контроллеру нужно уметь определять, какая строка в пределах данного подмножества самая «старая». Так как в каждом подмножестве всего 4 элемента, достаточно всего двух бит для хранения возраста строки́ (рисунок 5).

Рисунок 5. Строка четырёх-ассоциативной кэш-памяти
Кроме того, в строках кэша теперь не требуются устройства для одновременного сравнения тэгов и для одновременного увеличения возраста, так как эти операции нужно делать не со всеми строками кэш-памяти, а только с четырьмя строками за один раз. Эти 4 строки́ могут быть, например, просмотрены/обработаны контроллером по очереди, не сильно снижая быстродействие кэша.
Однако, можно добиться одновременной обработки четырёх строк кэша. Для этого разделим кэш-память на 4 равных части («банка»), и свяжем с каждым банком своё устройство управления (рисунок 6). При таком подходе каждое подмножество из четырёх одновременно обрабатываемых строк окажется распределённым по четырём банкам, каждый из которых может работать параллельно с остальными. При записи данных в кэш hint, выбираемый контроллером, фактически будет представлять собой номер банка, в который данные будут записаны.

Рисунок 6. Пример поиска данных в четырёх-ассоциативном кэше по адресу.
Модификация возраста строки́ не показана.
Нажмите на рисунок, чтобы увеличить
Когда процессор выдаёт запрос на чтение байта оперативной памяти, кэш-контроллер выполняет следующие действия:
- разбивает адрес требуемого байта на части (как показано на рисунке 4), определяя тэг, номер строки́ кэша, и смещение в строке;
- так как контроллер не знает, какое значение hint (номер банка) было выбрано им для этих данных, когда они записывались в кэш в прошлый раз (и записывались ли они вообще), контроллер, зная номер строки́ в банке, читает строки с этим номером одновременно со всех банков (см. рисунок 6), либо, если кэш не разбит на банки, читает четыре строки́ по очереди из кэш-памяти, подставляя в номер строки́ все возможные значения hint (см. рисунок 4);
- контроллер сверяет тэги прочитанных из кэш-памяти строк с тэгом, выделенным из адреса;
- если тэги не совпали (данные в кэше отсутствуют), выполняются следующие действия:
- среди четырёх прочитанных строк выбирается для замещения строка с максимальным возрастом (если кэш не разбит на банки, а имеет сквозную нумерацию строк, то это действие как раз и означает выбор значения hint контроллером); возраст этой строки́ обнуляется, возрасты остальных трёх строк увеличиваются на единицу;
- если бит модификации выбранной для замещения строки́ не равен нулю, то он обнуляется, и содержимое строки́ записывается в место оперативной памяти, определяемое хранящимся в строке тэгом и номером этой строки́ в банке;
- в выбранную для замещения строку кэша из оперативной памяти загружаются 16 байт, среди которых находится требуемый процессором байт памяти (адрес этой последовательности байт равен адресу требуемого байта, но с обнулёнными последними четырьмя битами);
- тэг строки́ заменяется на тэг, выделенный из адреса требуемого байта;
- теперь требуемые данные точно присутствуют в кэше (тэг одной из четырёх строк совпадает с тэгом, выделенным из адреса); контроллер увеличивает на единицу возраст тех строк (среди четырёх прочитанных), возраст которых меньше возраста строки́ с нужными данными, а возраст строки́ с нужными данными обнуляет;
- контроллер выдаёт байт процессору из строки́ кэша в соответствии со смещением, выделенным из адреса
Когда процессор выдаёт запрос на запись байта в оперативную память, кэш-контроллер выполняет следующие действия:
- разбивает адрес требуемого байта на части (как показано на рисунке 4), определяя тэг, номер строки́ кэша, и смещение в строке;
- контроллер, зная номер строки́ в банке, читает строки с этим номером одновременно со всех банков (см. рисунок 6).
- контроллер сверяет тэги прочитанных из кэш-памяти строк с тэгом, выделенным из адреса;
- если тэги не совпали (перезаписываемые данные не прокэшированы), то выполняются следующие действия:
- среди четырёх прочитанных строк выбирается для замещения строка с максимальным возрастом; её возраст обнуляется, возрасты остальных трёх строк увеличиваются на единицу;
- если бит модификации выбранной для замещения строки́ не равен нулю, то он обнуляется, и содержимое строки́ записывается в место оперативной памяти, определяемое хранящимся в строке тэгом и номером этой строки́ в банке;
- в выбранную для замещения строку кэша из оперативной памяти загружаются 16 байт, среди которых находится перезаписываемый процессором байт памяти (адрес этой последовательности байт равен адресу требуемого байта, но с обнулёнными последними четырьмя битами);
- тэг строки́ заменяется на тэг, выделенный из адреса требуемого байта;
- теперь перезаписываемые данные точно присутствуют в кэше; контроллер увеличивает на единицу возраст тех строк (среди четырёх прочитанных), возраст которых меньше возраста строки́ с нужными данными, а возраст строки́ с нужными данными обнуляет;
- контроллер модифицирует байт строки́ кэша в соответствии со смещением, выделенным из адреса;
- бит модификации строки́ устанавливается в 1.
Мы видим, что N-ассоциативный кэш можно понимать, как N кэшей с прямым отображением адресов, которые, в свою очередь, являются элементами полностью ассоциативного кэша. Контроллер, размещая данные в кэш-памяти, оптимально выбирает один из N элементов полностью ассоциативного кэша. А в выбранном кэше он помещает данные в строку, номер которой жёстко определяется адресом этих данных в оперативной памяти.
Кэш с прямым отображением адресов и полностью ассоциативный кэш являются частными случаями (крайностями) N-ассоциативного кэша. Если
, мы получаем кэш с прямым отображением адресов, если же N равно общему числу строк кэш-памяти, то получается полностью ассоциативный кэш.
N-ассоциативный кэш является самым распространённым видом кэша в современных компьютрерах, так как он гораздо эффективнее кэша с прямым отображением. В среднем, эффективность (отношение числа попаданий в кэш к общему числу обращений к памяти) работы двух-ассоциативного кэша объёмом V байт примерно равна эффективности работы кэша с прямым отображением объёмом
байт. Аналогично, четырёх-ассоциативный кэш в 1.5–2 раза эффективней, чем двух-ассоциативный. С дальнейшим увеличением ассоциативности увеличение эффективности не так значительно.
Страницы: 1 2.
Четыре отзыва на запись «Лекция № 7: Кэш процессора»
Автор: Андрей. Дата: 20-го апреля 2010 г. Время: 12:16.
Спасибо большое за материал.
Автор: Антон. Дата: 26-го января 2011 г. Время: 20:11.
Спасибо автору, статья отличная!
Автор: Вася. Дата: 25-го ноября 2011 г. Время: 13:52.
>Если данных в кэше нет, то самая старая строка вытесняется, и на её место записываются новые данные, опять же помеченные как изменённые
Не понятно — если линия считана и уже помечена как изменённая — тогда её надо будет сбросить в память даже если процессор в неё ничего не писал.
Автор: Вася. Дата: 25-го ноября 2011 г. Время: 13:56.
А, в смысле, имелось в виду что не загружена из памяти, а что процессор в неё записал, спасибо, теперь понятно.