Как я могу сделать очистку кеша процессора в Windows x86? - PullRequest
46 голосов
/ 18 ноября 2009

Я заинтересован в принудительной очистке кэша ЦП в Windows (для сравнения я хочу эмулировать запуск без данных в кэш-памяти ЦП), предпочтительно в базовой реализации C или вызове Win32.

Есть ли известный способ сделать это с помощью системного вызова или даже чего-то такого же подлого, как, например, большое memcpy?

Платформа Intel i686 (с P4 и выше тоже все в порядке).

Ответы [ 4 ]

52 голосов
/ 18 ноября 2009

К счастью, существует несколько способов явной очистки кэшей.

Инструкция "wbinvd" записывает обратно измененный контент кеша и помечает кеш пустым. Он выполняет цикл шины, чтобы внешние кэши сбрасывали свои данные. К сожалению, это привилегированная инструкция. Но если есть возможность запустить тестовую программу под чем-то вроде DOS, это путь. Это имеет преимущество, заключающееся в том, что размер кэша «ОС» остается очень маленьким.

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

Для сравнительного анализа простейшим решением, вероятно, является копирование большого блока памяти в область, отмеченную WC (объединение записи) вместо WB. Область отображения памяти графической карты является хорошим кандидатом, или вы можете пометить область как WC самостоятельно через регистры MTRR.

Информацию о тестировании коротких подпрограмм можно найти в Тестовых программах для измерения тактовых циклов и мониторинга производительности.

8 голосов
/ 18 ноября 2009

Существуют инструкции по сборке x86, заставляющие ЦП сбрасывать определенные строки кэша (например, CLFLUSH ), но они довольно неясны. В частности, CLFLUSH сбрасывает выбранный адрес из кэшей L1.

что-то подлое, как, скажем, большая записка?

Да, это самый простой подход, и он гарантирует, что ЦП сбрасывает все уровни кэша. Просто исключите время очистки кеша из ваших тестов производительности, и вы получите хорошее представление о том, как ваша программа работает под давлением кеша.

2 голосов
/ 18 ноября 2009

К сожалению, нет способа явно очистить кэш. Вот несколько вариантов:

1.) Уничтожьте кеш, выполняя очень большие операции с памятью между итерациями кода, который вы тестируете.

2.) Включить отключение кэша в x86 управляющих регистрах и сравнить его. Это, вероятно, также отключит кеш инструкций, что может не соответствовать вашим ожиданиям.

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

1, вероятно, самый простой и достаточный для ваших целей.

Редактировать : Упс, я исправлен. Есть инструкция по аннулированию кэша x86, см. Ответ drhirsch

1 голос
/ 10 мая 2019

Инструкция x86 WBINVD выполняет обратную запись и делает недействительными все кэши. Это описывается как :

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

Важно, что инструкция может быть выполнена только в ring0, то есть в операционной системе. Так что ваши пользовательские программы не могут просто использовать его. В Linux вы можете написать модуль ядра, который может выполнять эту инструкцию по требованию. На самом деле, кто-то уже написал такой модуль ядра: https://github.com/batmac/wbinvd

К счастью, код модуля ядра действительно крошечный, так что вы можете проверить его перед загрузкой кода из незнакомых людей из Интернета в ваше ядро. Вы можете использовать этот модуль (и запустить выполнение команды WBINVD), прочитав /proc/wbinvd, например, через cat /proc/wbinvd.

Однако я обнаружил, что эта инструкция (или, по крайней мере, этот модуль ядра) действительно медленная. На моем i7-6700HQ я измерил его на 750 мкс! Это число мне кажется очень высоким, поэтому я мог ошибиться, измерив это - пожалуйста, имейте это в виду! Объяснение этой инструкции просто сказать:

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

...