Я хочу проверить производительность программы пользовательского пространства в 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));
}
Он успешно скомпилирован, но результаты синхронизации не изменились. Я подозреваю, что компилятор удалил его с целью оптимизации. У кого-нибудь есть идеи, как я могу решить эту проблему?
#include <asm/cachectl.h>?
Используйте _mm_clflush из emmintrin.h и имейте в виду, что создание флеша требует времени.
@Jesper, язык не заботится о производительности, но реальные реализации, и этот пользователь, так что я не уверен, что это имеет значение.
@JesperJuhl, спасибо. Я не беспокоюсь о языке. Я измеряю производительность некоторых вычислений на x86 по сравнению с ARM. В версии ARM данные не кэшируются, а в версии x86 кэшируются. Итак, мне нужно очистить эту строку кеша, чтобы иметь справедливое сравнение.
@Swordfish, Спасибо! когда я включаю этот заголовочный файл, я получаю следующую ошибку: фатальная ошибка: asm/cachectl.h: нет такого файла или каталога
то cachectl() недоступен для вашей платформы.
@FilipDimitrovski, спасибо! Я попробовал _mm_clflush из x86intrin.h. Он скомпилирован правильно, но результаты синхронизации совпадают. Я начинаю подозревать, что предварительная выборка x86 неплохо справляется со своей задачей. Хотя я не могу этого доказать.
Невозможно ответить на этот вопрос, не показывая весь код.
Нам также нужно знать процессор, на котором вы запускаете код, и точную команду, используемую для его компиляции.





Второй сбрасывает память, содержащую указатель __p, который находится в стеке, поэтому он не дает нужного вам эффекта.
Проблема с первым в том, что он использует макрос __force, который определен в ядре Linux и здесь не нужен. (Что делает __attribute__((force))?)
Если вы удалите __force, он будет делать то, что вы хотите.
(Вы также должны изменить его, чтобы не использовать имя переменной __p, которое является зарезервированным идентификатором.)
Если вы сбрасываете большое количество строк кеша, вы можете изменить его на использование clflushopt (если ваш процессор поддерживает это), а sfence следует за всеми сбросами.
Спасибо. Удалил __force и скомпилировал. Но результаты такие же. Как я упоминал выше, я начинаю подозревать, что предварительная выборка x86 делает довольно хорошую работу.
Это был бы еще лучший ответ, если бы вы указали, что вместо этого следует использовать _mm_clflush. И это asm volatile означает, что он определенно не оптимизирован.
@HodaAgheikhouzani: предварительная выборка HW очень хорошо работает для последовательного доступа, но она не может справиться с касанием 1 int на строку кэша или что-то в этом роде с шагом 64 байта. Если ваш реальный код работает намного медленнее, например, несколько тактов на строку кэша, то да, он вполне может не отставать даже от DRAM.
@PeterCordes, спасибо! Код представляет собой последовательный доступ к большому массиву, поэтому очистка кеша не повлияет на задержку.
C++ как правило работает на гораздо более высоком уровне, чем этот. Это не то, чем вы обычно должны заниматься в том, что касается языка.