Как очистить кэш процессора для области адресного пространства в Linux?

Меня интересует очистка кэша (L1, L2 и L3) только для области адресного пространства, например, для всех записей кэша от адреса A до адреса B. Существует ли механизм для этого в Linux, либо из пространства пользователя или ядра?

4 ответа

Решение

Проверьте эту страницу для списка доступных методов очистки в ядре Linux: https://www.kernel.org/doc/Documentation/cachetlb.txt

Кэш и TLB Flushing под Linux. Дэвид С. Миллер

Есть набор функций промывки диапазона

2) flush_cache_range(vma, start, end);
   change_range_of_page_tables(mm, start, end);
   flush_tlb_range(vma, start, end);

3) void flush_cache_range(struct vm_area_struct *vma, длинный без знака, длинный конец без знака)

Here we are flushing a specific range of (user) virtual
addresses from the cache.  After running, there will be no
entries in the cache for 'vma->vm_mm' for virtual addresses in
the range 'start' to 'end-1'.

Вы также можете проверить реализацию функции - http://lxr.free-electrons.com/ident?a=sh;i=flush_cache_range

Например, на руках - http://lxr.free-electrons.com/source/arch/arm/mm/flush.c?a=sh&v=3.13#L67

 67 void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 68 {
 69         if (cache_is_vivt()) {
 70                 vivt_flush_cache_range(vma, start, end);
 71                 return;
 72         }
 73 
 74         if (cache_is_vipt_aliasing()) {
 75                 asm(    "mcr    p15, 0, %0, c7, c14, 0\n"
 76                 "       mcr     p15, 0, %0, c7, c10, 4"
 77                     :
 78                     : "r" (0)
 79                     : "cc");
 80         }
 81 
 82         if (vma->vm_flags & VM_EXEC)
 83                 __flush_icache_all();
 84 }

Это для ARM.

GCC обеспечивает __builtin___clear_cache который должен сделать системный вызов cacheflush, Однако у этого могут быть свои предостережения.

Здесь важно то, что Linux обеспечивает системный вызов (специфичный для ARM) для очистки кэшей. Вы можете проверить Android / Bionic flushcache, как использовать этот системный вызов. Однако я не уверен, какие гарантии дает Linux, когда вы его называете, или как это реализовано через его внутреннюю работу.

Этот пост в блоге Кэши и самоизменяющийся код могут помочь в дальнейшем.

В x86 версии Linux вы также можете найти функцию void clflush_cache_range(void *vaddr, unsigned int size) который используется для очистки диапазона кэша. Эта функция опирается на CLFLUSH или же CLFLUSHOPT инструкции. Я бы порекомендовал проверить, действительно ли ваш процессор поддерживает их, потому что теоретически они не являются обязательными.

CLFLUSHOPT слабо упорядочен. CLFLUSH изначально был указан как заказанный только MFENCE, но все процессоры, которые его реализуют, делают это с сильным упорядочением по отношению к пишет и прочее CLFLUSH инструкции. Intel решила добавить новую инструкцию (CLFLUSHOPT) вместо изменения поведения CLFLUSH и обновить руководство, чтобы гарантировать, что будущие процессоры будут реализовывать CLFLUSH как сильно приказал. Для этого вы должны MFENCE после использования любого из них, чтобы убедиться, что промывка выполняется до любых нагрузок от вашего эталона (а не только магазины).

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

Также обратите внимание, что эти инструкции являются когерентными. Их выполнение повлияет на все кэши всех процессоров (процессорных ядер) в системе.

Все эти три инструкции доступны в пользовательском режиме. Таким образом, вы можете нанять ассемблер и создать свой собственный void clflush_cache_range(void *vaddr, unsigned int size) в вашем пользовательском пространстве приложения (но не забудьте проверить их наличие, перед фактическим использованием).


Если я правильно понимаю, в этом отношении рассуждать об ARM гораздо сложнее. Семейство ARM-процессоров гораздо менее последовательное, чем семейство процессоров IA-32. У вас может быть один ARM с полнофункциональными кешами, а другой полностью без кешей. Более того, многие производители могут использовать индивидуальные MMU и MPU. Так что лучше рассуждать о какой-то конкретной модели процессора ARM.

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


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

И TLB не является связным, в отличие от кэшей памяти. Будьте осторожны, поскольку сброс записей TLB не приводит к сбросу соответствующих данных из кэша памяти.

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


PLD / LDR

Можно изгнать кеши, неправильно используя pld инструкция. pld извлечет строку кэша. Чтобы удалить конкретный адрес памяти, вам нужно знать структуру ваших кешей. Например, cortex-a9 имеет 4-х сторонний кеш данных с 8 словами в строке. Размер кэша настраивается в 16 КБ, 32 КБ или 64 КБ. Это 512, 1024 или 2048 строк. Пути всегда незначительны для младших битов адреса (поэтому последовательные адреса не конфликтуют). Таким образом, вы получите новый способ доступа к memory offset + cache size / ways, То есть каждые 4 КБ, 8 КБ и 16 КБ для cortex-a9.

С помощью ldr в "C" или "C++" просто. Вам просто нужно соответствующим образом определить размер массива и получить к нему доступ.

Смотрите: Программно получить размер строки кэша?

Например, если вы хотите исключить 0x12345, строка начинается с 0x12340 и для циклического кэширования размером 16 КБ a pld в 0x13340, 0x14340, 0x15340 и 0x16340 будут исключены любые значения формы таким образом. Тот же принцип может быть применен к выселению L2 (который часто унифицирован). Итерирование по всему размеру кэша приведет к удалению всего кэша. Вам нужно выделить неиспользуемую память размером кеша, чтобы полностью его удалить. Это может быть довольно большим для L2. pld не нужно использовать, но полный доступ к памяти (ldr/ldm). Для нескольких процессоров (вытеснение из многопоточного кэша) вам нужно запустить вытеснение на каждом процессоре. Обычно L2 является глобальным для всех процессоров, поэтому его нужно запускать только один раз.

NB. Этот метод работает только с LRU (используется в последнее время) или с циклическим кэшем. Для псевдослучайной замены вам нужно будет записать / прочитать больше данных, чтобы гарантировать выселение, причем точное количество будет сильно зависеть от процессора. Случайная замена ARM основана на LFSR от 8 до 33 бит в зависимости от процессора. Для некоторых процессоров по умолчанию используется циклический перебор, а для других - по умолчанию псевдослучайный режим. Для нескольких процессоров в конфигурации ядра Linux будет выбран режим. ref: CPU_CACHE_ROUND_ROBIN Однако для более новых процессоров Linux будет использовать значение по умолчанию из загрузчика и / или кремния. Другими словами, стоит попытаться получить clear_cache ОС призывает работать (см. Другие ответы), если вам нужно быть полностью универсальным или вам придется потратить много времени, чтобы надежно очистить кэш.

Контекст свич

Можно обойти кеш, обманывая ОС, используя MMU на некоторых процессорах ARM и определенных ОС. В системе *nix вам нужно несколько процессов. Вам нужно переключаться между процессами, а ОС должна очищать кеш. Как правило, это будет работать только на старых процессорах ARM (те, которые не поддерживают pld) где ОС должна очищать кэши, чтобы не было утечки информации между процессами. Он не переносимый и требует, чтобы вы много понимали в своей ОС.

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

В x86 для очистки всей иерархии кеша вы можете использовать это

native_wbinvd()

Который определен в arch/x86/include/asm/special_insns.h . Если вы посмотрите на его реализацию, он просто вызывает инструкцию WBINVD

static inline void native_wbinvd(void)
{
        asm volatile("wbinvd": : :"memory");
}

Обратите внимание, что для выполнения инструкции WBINVD X86 вам нужно находиться в привилегированном режиме. Это отличается от инструкции CLFLUSH x86, которая очищает одну строку кэша и не требует, чтобы вызывающий абонент находился в привилегированном режиме.

Если вы посмотрите на код ядра x86 Linux, вы увидите только несколько (6 мест, когда я пишу это) этой инструкции. Это потому, что это замедляет все объекты, работающие в этой системе. Представьте себе запуск этого на сервере с 100 МБ LLC. Эта инструкция будет означать перемещение всех 100+ МБ из кэша в оперативную память. Кроме того, мне стало известно, что эта инструкция не прерывается. Таким образом, его использование может значительно повлиять на детерминизм системы RT, например,

(Хотя первоначальный вопрос спрашивает о том, как очистить определенный диапазон адресов, я подумал, что информация об очистке всей иерархии кэша также будет полезна для некоторых читателей)

Другие вопросы по тегам