C изменчивые переменные и кэш-память
Кэш контролируется аппаратным обеспечением кэширования прозрачно для процессора, поэтому, если мы используем переменные volatile в программе на C, как гарантируется, что моя программа каждый раз считывает данные с указанного фактического адреса памяти, но не кэша.
Я понимаю, что
-
Волатированное ключевое слово сообщает компилятору, что ссылки на переменные не должны быть оптимизированы и должны быть прочитаны как запрограммированные в коде.
-
Кэш контролируется аппаратным обеспечением кеша прозрачно, поэтому, когда процессор выдает адрес, он не знает, поступают ли данные из кеша или из памяти.
Итак, если у меня есть требование, чтобы каждый раз читать адрес памяти, как я могу убедиться, что его не отсылают из кеша, но из требуемого адреса?
Некоторые, как, эти два понятия плохо подходят друг другу. Просьба уточнить, как это делается.
(Представьте, что у нас есть политика обратной записи в кеше (если это необходимо для анализа проблемы))
Спасибо,
Микроядро:)
Ответы
Ответ 1
Разработчик прошивки здесь. Это стандартная проблема во встроенном программировании, а также одна из них, которая помогает многим (даже очень опытным) разработчикам.
Мое предположение заключается в том, что вы пытаетесь получить доступ к регистру оборудования, и это значение регистра может меняться со временем (будь то состояние прерывания, таймер, показания GPIO и т.д.).
Ключевое слово volatile
является лишь частью решения, и во многих случаях может и не понадобиться. Это заставляет переменную перечитывать из памяти каждый раз, когда она используется (в отличие от оптимизации компилятором или хранения в регистре процессора для нескольких применений), но является ли считанная "память" фактическим аппаратным регистром по сравнению с кэшированным местоположением, неизвестно вашему коду и не подвержено влиянию ключевого слова volatile
. Если ваша функция только считывает регистр один раз, вы можете, возможно, оставить volatile
, но, как правило, я предлагаю, чтобы большинство аппаратных регистров определялось как volatile
.
Большая проблема заключается в кешировании и кешировании. Самый простой способ заключается в том, чтобы убедиться, что ваш регистр находится в нераспространенном адресном пространстве. Это означает, что каждый раз, когда вы обращаетесь к регистру, вы гарантированно читаете/записываете фактический регистр оборудования, а не кэш-память. Более сложный, но потенциально более эффективный подход заключается в использовании кэшированного адресного пространства, и ваш код вручную принудительно обновляет кеш файлы для конкретных ситуаций, подобных этому. Для обоих подходов, как это делается, зависит от архитектуры и выходит за рамки вопроса. Это может включать MTRR (для x86), MMU, изменения в таблицах страниц и т.д.
Надеюсь, что это поможет. Если я что-то пропустил, дайте мне знать, и я расширю свой ответ.
Ответ 2
Мое предложение состоит в том, чтобы пометить страницу как не кэшированную диспетчером виртуальной памяти.
В Windows это делается с помощью PAGE_NOCACHE
при вызове VirtualProtect
.
Для несколько иной цели в инструкциях SSE 2 есть инструкции _mm_stream_xyz
, чтобы предотвратить загрязнение кеша, хотя я не думаю, что они применимы к вашему делу здесь.
В любом случае нет портативного способа делать то, что вы хотите в C; вы должны использовать функциональность ОС.
Ответ 3
Из вашего вопроса есть заблуждение с вашей стороны.
Volatile
ключевое слово не связано с кешем, как вы описываете.
Если для переменной указано ключевое слово Volatile
, оно дает подсказку компилятору не выполнять определенные оптимизации, так как эта переменная может неожиданно изменяться с других частей программы.
Здесь имеется в виду, что компилятор не должен повторно использовать значение , уже загруженное в регистр, но снова получить доступ к памяти, так как значение в регистре не гарантируется таким же, как значение хранится в памяти.
Остальные, относящиеся к кеш-памяти, напрямую не связаны с программистом.
Я имею в виду, что синхронизация любой кэш-памяти CPU с ОЗУ - совсем другой предмет.
Ответ 4
В Википедии есть довольно хорошая статья о MTRR (регистры диапазона типов памяти), которые относятся к семейству процессоров x86.
Подводя итог этому, начиная с процессора Intel Pentium Pro (и с копией AMD), эти регистры MTR могли устанавливать в диапазонах памяти нераскрытые, записываемые, записываемые, записываемые, защищенные от записи или записываемые атрибуты.
Начиная с Pentium III, но, насколько я знаю, только очень полезно для 64-битных процессоров, они уважают MTRR, но их можно переопределить таблицами атрибутов страниц, которые позволяют процессору устанавливать тип памяти для каждой страницы памяти.
Основное использование MTRR, о котором я знаю, - это графическая RAM. Гораздо эффективнее отметить это как объединение записи. Это позволяет кешу хранить записи и отменяет все правила упорядочивания записи в памяти, чтобы обеспечить высокоскоростную запись на видеокарте.
Но для ваших целей вам понадобится либо MTRR, либо PAT-настройка как нераскрытого, так и сквозного.
Ответ 5
используя ключевое слово _Uncached, может помочь во встроенной ОС, например MQX
#define MEM_READ(addr) (*((volatile _Uncached unsigned int *)(addr)))
#define MEM_WRITE(addr,data) (*((volatile _Uncached unsigned int *)(addr)) = data)
Ответ 6
Как вы говорите, кеш прозрачен для программиста. Система гарантирует, что вы всегда увидите значение, которое было записано в последний раз, если вы обращаетесь к объекту по его адресу. "Единственное", что вы можете понести, если устаревшее значение находится в вашем кеше, - это штраф за выполнение.
Ответ 7
volatile
гарантирует, что данные считываются каждый раз, когда это необходимо, не беспокоясь о кеше между ЦП и памятью. Но если вам нужно прочитать фактические данные из памяти, а не кэшированные данные, у вас есть два варианта:
- Создайте доску, где данные не кэшируются. Возможно, это может произойти, если вы обращаетесь к некоторому устройству ввода/вывода,
- Используйте специальные инструкции CPU, которые обходят кеш. Это используется, когда вам нужно очистить память для активации возможных ошибок SEU.
Детали второй опции зависят от ОС и/или ЦП.