Библиотека сайта rus-linux.net
Что каждый программист должен знать о памяти.
Часть 2: Кэш-память процессора
Оригинал: "Memory part 2: CPU caches"Автор: Ulrich Drepper
Дата публикации: October 1, 2007
Перевод: Н.Ромоданов
Дата перевода: апрель 2012 г.
Назад | Оглавление | Вперед |
3.3.3 Запись данных
Прежде, чем переходить к изучению поведения кэш-памяти в случае, одна и та же память используется в нескольких контекстах исполнения (потоках или процессах), рассмотрим детали реализации кэш-памяти. Предполагается, что кэш-память однородная, а также предполагается, что ее однородность полностью прозрачна для кода пользовательского уровня. Код ядра это уже другая история; для него иногда требуется принудительное сохранение содержимого кэш-памяти.
В частности, это значит, что если кэш-строка изменена, то после этого момента результат для системы должен быть точно такой же, как если бы кэш-памяти вообще не было и изменялось содержимое основной памяти. Это можно реализовывать двумя способами или политиками:
- реализация кэш-памяти с прямой записью;
- реализация кэш-памяти с обратной записью.
Кэш-память с прямой записью является самым простым способом реализации однородности кэш-памяти. Если выполняется запись в кэш-строку, то процессор сразу же запишет кэш-строку в основную память. Это гарантирует, что в любой момент времени оперативная память и кэш-память будут синхронизированы. Всякий раз, когда происходит замена содержимого кэш-памяти, предыдущее содержимое может быть просто затерто. Такая политика работы с кэш-памятью очень проста, но не очень быстрая. Программа, которая, например, снова и снова изменяет локальные переменные, будет создавать большой объем трафика на шине FSB даже в случае, если данные, вероятно, нигде больше не используются и нужны на короткое время.
Политика с обратной записью является более сложной. Здесь процессор не будет сразу записывать модифицированную кэш-строку орбратно в основную память. Вместо этого, кэш-строка только помечается, как измененная. Когда кэш-строка удаляется из кэш-памяти в какой-то момент в будущем, то бит, указывающий на то, что данные изменились, будет указывать процессору записывать в этот момент данные обратно в основную память, а не просто их удалять.
У кэш-памяти с обратной записью есть шанс быть значительно эффективней и благодаря этому большая часть памяти в системе с приличным процессором кэшируется именно таким образом. Процессор перед тем, как кэш-строка будет переслана, может даже воспользоваться свободными ресурсами шины FSB для хранения содержимого кэш-строки. Благодаря этому можно сбросить бит, указывающий на изменение, и, когда в кэш-памяти потребуется место, то просто стереть содержимое кэш-строки.
Но с реализацией кэш-памяти с обратной записью есть серьезная проблема. Когда есть несколько процессоров (или ядер или гиперпотоков), имеющих доступ к одной и той же памяти, нужно еще обеспечить, чтобы в любой момент времени все процессоры видели одно и то же содержимое памяти. Если в одном процессоре кэш-строка изменена (т.е. она еще не была записана обратно в память), а второй процессор пытается прочитать это место памяти, операция чтения не может просто обратиться к основной памяти. Вместо нее требуется содержимое кэш-строки первого процессора. В следующем разделе мы увидим, как в настоящее время это реализуется.
Прежде, чем мы перейдем к этому, нужно упомянуть еще две политики работы с кэш-памятью:
- комбинированная запись и
- отсутствие кэширования.
Обе эти политики используются для специальных областей адресного пространства, которые не закреплены за реально существующей оперативной памятью. Ядро устанавливает эти политики для диапазонов адресов (в процессорах x86 используются регистры диапазонов типа памяти - Memory Type Range Registers или MTRR), а остальное происходит автоматически. Регистры MTRR также используются для выбора политик прямой и обратной записи.
Политика комбинированной записи является ограниченным вариантом оптимизации кэширования, который чаще используются для памяти таких устройств, как видеокарты. Поскольку затраты на передачу данных в устройство намного выше, чем затраты на локальный доступ к памяти, в случае, когда нужно сократить объем передаваемых данных, важность это политики становится еще большей. Если с помощью следующей операции изменяется следующее слово, то передача всей кэш-строки только потому, что в строку было записано слово, будет расточительным. Можно легко предположить, что когда память для соседних по горизонтали пикселей, расположенных на экране, в большинстве случаев будет также в памяти расположена по соседству друг с другом, является типичной ситуацией. Прежде, чем кэш-строка будет записана обратно в память, при комбинированной политике, как следует из названия, будут применены несколько режимов доступа. В идеальном случае вся кэш-строка изменяется слово за словом, и только после того, как будет записано последнее слово, кэш-строка будет переписана в устройство. В результате можно существенно увеличить скорость доступа к оперативной памяти устройства.
Наконец, есть некэшируемая память. Как правило, это означит, что эта память вообще не является оперативной памятью. Это может быть специальный адрес, который для того, чтобы к некоторым функциям можно было обращаться помимо процессора, указывается жестско. Что касается аппаратных средств, то это чаще всего связано с диапазонами адресов, отображаемых в память, которые используются для трансляции адресов при доступе к картам и устройствам через шину (PCIe и т.д.). Во встраиваемых устройствах иногда есть такие адреса памяти, которые можно использовать для включения и выключения светодиодного индикатора. Очевидно, что кэширование такого адреса будет плохим решением. Светодиоды в подобных случаях используется для отладки и информировании о состоянии устройства и эту информацию хочется увидеть как можно скорее. Содержимое памяти в картах PCIe может изменяться без вмешательства процессора, так что эта память не должна кэшироваться.
Назад | Оглавление | Вперед |