Как очистить диапазон адресов в кеше процессора?

Я хочу проверить производительность программы пользовательского пространства в Linux, работающей на x86. Чтобы рассчитать производительность, мне необходимо сбросить в память определенные строки кеша (убедитесь, что эти строки недействительны, и при следующем запросе будет промах кеша).

Я уже видел предложения с использованием cacheflush(2), который должен быть системным вызовом, но g++ жалуется на то, что он не объявлен. Кроме того, я не могу использовать clflush_cache_range, который, по-видимому, может быть вызван только в программе ядра. Прямо сейчас я попытался использовать следующий код:

static inline void clflush(volatile void *__p)
{
    asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p));
}

Но это дает следующую ошибку при компиляции:

ошибка: ожидаемое первичное выражение перед 'volatile'

Затем я изменил его следующим образом:

static inline void clflush(volatile void *__p)
{
    asm volatile("clflush %0" :: "m" (__p));
}

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


person Hoda Aghaeikhouzani    schedule 08.05.2019    source источник
comment
C++ обычно работает на гораздо более высоком уровне, чем этот. Это не то, чем вы обычно должны заниматься в том, что касается языка.   -  person Jesper Juhl    schedule 08.05.2019
comment
g++ жалуется на то, что он не объявлен.#include <asm/cachectl.h>?   -  person Swordfish    schedule 08.05.2019
comment
Используйте _mm_clflush из emmintrin.h и имейте в виду, что создание флеша требует времени.   -  person Filip Dimitrovski    schedule 08.05.2019
comment
@Jesper, язык не заботится о производительности, но реальные реализации, и этот пользователь, так что я не уверен, что это имеет значение.   -  person prl    schedule 08.05.2019
comment
@JesperJuhl, спасибо. Я не беспокоюсь о языке. Я измеряю производительность некоторых вычислений на x86 по сравнению с ARM. В версии ARM данные не кэшируются, а в версии x86 кэшируются. Итак, мне нужно очистить эту строку кеша, чтобы иметь справедливое сравнение.   -  person Hoda Aghaeikhouzani    schedule 08.05.2019
comment
@Swordfish, Спасибо! когда я включаю этот заголовочный файл, я получаю следующую ошибку: фатальная ошибка: asm/cachectl.h: нет такого файла или каталога   -  person Hoda Aghaeikhouzani    schedule 08.05.2019
comment
то cachectl() недоступен для вашей платформы.   -  person Swordfish    schedule 08.05.2019
comment
@FilipDimitrovski, спасибо! Я попробовал _mm_clflush из x86intrin.h. Он скомпилирован правильно, но результаты синхронизации совпадают. Я начинаю подозревать, что предварительная выборка x86 неплохо справляется со своей задачей. Хотя я не могу этого доказать.   -  person Hoda Aghaeikhouzani    schedule 08.05.2019
comment
Невозможно ответить на этот вопрос, не показывая весь код.   -  person Hadi Brais    schedule 09.05.2019
comment
Нам также нужно знать процессор, на котором вы запускаете код, и точную команду, используемую для его компиляции.   -  person Hadi Brais    schedule 09.05.2019


Ответы (1)


Второй сбрасывает память, содержащую указатель __p, который находится в стеке, поэтому он не дает нужного вам эффекта.

Проблема с первым в том, что он использует макрос __force, который определен в ядре Linux и здесь не нужен. (Что делает __attribute__((force))?)

Если вы удалите __force, он будет делать то, что вы хотите.

(Вы также должны изменить его, чтобы избежать использования имени переменной __p, которое является зарезервированным идентификатором.)

person prl    schedule 08.05.2019
comment
Если вы сбрасываете большое количество строк кеша, вы можете изменить его, чтобы использовать clflushopt (если ваш процессор поддерживает это), с sfence после всех очисток. - person prl; 08.05.2019
comment
Спасибо. Удалил __force и скомпилировал. Но результаты такие же. Как я упоминал выше, я начинаю подозревать, что предварительная выборка x86 делает довольно хорошую работу. - person Hoda Aghaeikhouzani; 08.05.2019
comment
Это был бы еще лучший ответ, если бы вы указали, что вместо этого следует использовать _mm_clflush. И этот asm volatile означает, что он определенно не оптимизирован. - person Peter Cordes; 09.05.2019
comment
@HodaAgheikhouzani: аппаратная предварительная выборка очень хорошо работает для последовательного доступа, но она не может справиться с касанием 1 int на строку кэша или что-то в этом роде с шагом 64 байта. Если ваш реальный код работает намного медленнее, например, несколько тактов на строку кэша, то да, он вполне может не отставать даже от DRAM. - person Peter Cordes; 09.05.2019
comment
@PeterCordes, спасибо! Код представляет собой последовательный доступ к большому массиву, поэтому очистка кеша не повлияет на задержку. - person Hoda Aghaeikhouzani; 09.05.2019