С изменчивые переменные и кэш-память - PullRequest
33 голосов
/ 24 октября 2011

Кэш контролируется аппаратным обеспечением кеша прозрачно для процессора, поэтому, если мы используем изменчивые переменные в программе на C, как гарантируется, что моя программа считывает данные каждый раз с фактического указанного адреса памяти, но не из кэша.

Насколько я понимаю,

  1. Volatile ключевое слово сообщает компилятору, что ссылки на переменные не должны быть оптимизированы и должны читаться так, как запрограммировано в коде.

  2. Кэш-память прозрачно контролируется аппаратным обеспечением кеша, поэтому, когда процессор выдает адрес, он не знает, поступают ли данные из кеша или памяти.

Итак, если у меня есть требование читать каждый раз адрес памяти, как я могу убедиться, что он не ссылается из кэша, а с требуемого адреса?

Каким-то образом эти два понятия плохо сочетаются друг с другом.Пожалуйста, уточните, как это делается.

(Представьте, что у нас есть политика обратной записи в кеше (если требуется для анализа проблемы))

Спасибо, Microkernel:)

Ответы [ 7 ]

31 голосов
/ 24 октября 2011

Прошивка разработчика здесь. Это стандартная проблема во встроенном программировании, которая ставит в тупик многих (даже очень опытных) разработчиков.

Я предполагаю, что вы пытаетесь получить доступ к аппаратному регистру, и это значение регистра может со временем изменяться (будь то состояние прерывания, таймер, индикация GPIO и т. Д.).

Ключевое слово volatile является лишь частью решения, и во многих случаях может не потребоваться. Это приводит к тому, что переменная будет перечитываться из памяти каждый раз, когда она используется (в отличие от оптимизации компилятором или сохранения в регистре процессора при многократном использовании), но не является ли " память " читаемая информация является фактическим аппаратным регистром, в отличие от кэшированного местоположения, которое неизвестно вашему коду и не зависит от ключевого слова volatile. Если ваша функция читает регистр только один раз, то вы, вероятно, можете отключить volatile, но, как правило, я предлагаю, чтобы большинство аппаратных регистров было определено как volatile.

Большая проблема - кеширование и когерентность кеша. Самый простой подход - убедиться, что ваш регистр находится в не кэшированном адресном пространстве. Это означает, что каждый раз, когда вы получаете доступ к регистру, вы гарантированно читаете / записываете фактический аппаратный регистр, а не кэш-память. Более сложный, но потенциально более эффективный подход состоит в том, чтобы использовать кэшированное адресное пространство и заставить ваш код вручную принудительно обновлять кеш для определенных ситуаций, подобных этой. Для обоих подходов то, как это достигается, зависит от архитектуры и выходит за рамки вопроса. Это может включать MTRR (для x86), MMU, модификации таблицы страниц и т. Д.

Надеюсь, это поможет. Если я что-то пропустил, дайте мне знать, и я расширю свой ответ.

7 голосов
/ 24 октября 2011

От вашего вопроса есть неправильное представление с вашей стороны.
Ключевое слово Volatile не связано с кешем, как вы описываете.

Если для переменной указано ключевое слово volatile, это дает подсказку компилятору не выполнять определенные оптимизации, поскольку эта переменная может неожиданно измениться из других частей программы.

Здесь подразумевается, что компилятор не должен повторно использовать значение , уже загруженное в регистр , но снова обращаться к памяти, поскольку значение в регистре не гарантируется как значение, сохраненное в памяти.

Остальное, что касается кеш-памяти, не имеет прямого отношения к программисту.

Я имею в виду, что синхронизация любой кэш-памяти ЦП с ОЗУ - это совершенно другая тема.

7 голосов
/ 24 октября 2011

Я предлагаю пометить страницу как некэшируемую менеджером виртуальной памяти.
В Windows это делается путем установки PAGE_NOCACHE при вызове VirtualProtect.

Для несколько иной цели инструкции SSE 2 содержат инструкции _mm_stream_xyz для предотвращения загрязнения кэша, хотя я не думаю, что они применимы к вашему делу.

В любом случае переносимый способ делать то, что вы хотите в C;Вы должны использовать функциональность ОС.

2 голосов
/ 24 октября 2011

В Википедии есть довольно хорошая статья о MTRR (регистры диапазона типов памяти) , которые относятся к процессорам семейства x86.

Подводя итог, можно сказать, что начиная с Pentium Pro Intel (и AMD скопировали) имели эти регистры MTR, которые могли устанавливать атрибуты без кэширования, сквозной записи, комбинирования записи, защиты от записи или обратной записи в диапазонах памяти.

Начиная с Pentium III, но, насколько мне известно, они действительно полезны только для 64-разрядных процессоров, они учитывают MTRR, но их можно переопределить в таблицах атрибутов страницы, которые позволяют ЦП устанавливать тип памяти для каждой страницы. памяти.

Основное использование известных мне MTRR - графическая память. Гораздо эффективнее пометить его как комбинирующий запись. Это позволяет кэш-памяти хранить записи и ослабляет все правила упорядочения записи в память, чтобы обеспечить возможность высокоскоростной пакетной записи на видеокарту.

Но для ваших целей вам понадобится либо MTRR, либо параметр PAT либо без кэширования, либо с возможностью записи.

1 голос
/ 18 декабря 2012

использование ключевого слова _Uncached может помочь во встроенной ОС, например MQX

#define MEM_READ(addr)       (*((volatile _Uncached unsigned int *)(addr)))
#define MEM_WRITE(addr,data) (*((volatile _Uncached unsigned int *)(addr)) = data)
0 голосов
/ 24 октября 2011

volatile гарантирует, что данные читаются каждый раз, когда это необходимо, не беспокоясь о кеше между процессором и памятью. Но если вам нужно прочитать фактические данные из памяти, а не из кэшированных данных, у вас есть два варианта:

  • Создайте доску, где указанные данные не кэшируются. Это может уже иметь место, если вы обращаетесь к какому-либо устройству ввода / вывода,
  • Используйте специальные инструкции процессора, которые обходят кеш. Это используется, когда вам нужно очистить память для активации возможных ошибок SEU.

Детали второго параметра зависят от ОС и / или процессора.

0 голосов
/ 24 октября 2011

Как вы говорите, кеш прозрачен для программиста.Система гарантирует, что вы всегда видите значение, которое было записано в последний раз, если вы обращаетесь к объекту через его адрес.«Единственная» вещь, которую вы можете понести, если устаревшее значение находится в вашем кэше, - это штраф за время выполнения.

...