Кэш-связные системы делают все возможное, чтобы скрыть такие вещи от вас.Я думаю, что вам придется наблюдать это косвенно, либо используя регистры подсчета производительности для обнаружения ошибок в кеше, либо тщательно измеряя время для чтения области памяти с таймером высокого разрешения.
Эта программа работает на моем компьютере x86_64продемонстрировать эффекты clflush
.Время, необходимое для чтения глобальной переменной, используя rdtsc
.Будучи единственной инструкцией, привязанной непосредственно к тактовой частоте процессора, для этого идеально подходит rdtsc
.
Вот вывод:
took 81 ticks
took 81 ticks
flush: took 387 ticks
took 72 ticks
Вы видите 3 испытания: Первое гарантирует i
находится в кеше (это так, потому что он был только обнулен как часть BSS), второе - чтение i
, которое должно быть в кеше.Затем clflush
выбрасывает i
из кэша (вместе со своими соседями) и показывает, что повторное чтение занимает значительно больше времени.Окончательное чтение подтверждает, что оно снова в кеше.Результаты очень воспроизводимы, и разница достаточно существенна, чтобы легко увидеть ошибки в кеше.Если вы захотите откалибровать служебные данные rdtsc()
, вы можете сделать разницу еще более заметной.
Если вы не можете прочитать адрес памяти, который хотите проверить (хотя даже mmap
из /dev/mem
следуетработать для этих целей) вы можете сделать вывод, что вы хотите, если вы знаете размер строки кэширования и ассоциативность кэша.Затем вы можете использовать доступные области памяти для проверки активности в интересующем вас наборе.
Исходный код:
#include <stdio.h>
#include <stdint.h>
inline void
clflush(volatile void *p)
{
asm volatile ("clflush (%0)" :: "r"(p));
}
inline uint64_t
rdtsc()
{
unsigned long a, d;
asm volatile ("rdtsc" : "=a" (a), "=d" (d));
return a | ((uint64_t)d << 32);
}
volatile int i;
inline void
test()
{
uint64_t start, end;
volatile int j;
start = rdtsc();
j = i;
end = rdtsc();
printf("took %lu ticks\n", end - start);
}
int
main(int ac, char **av)
{
test();
test();
printf("flush: ");
clflush(&i);
test();
test();
return 0;
}