Есть ли способ проверить, был ли недавно очищен кеш процессора?

На i386 linux. Предпочтительно в c/(c/posix std libs)/proc, если это возможно. Если нет, есть ли какая-либо часть сборки или сторонняя библиотека, которая может это сделать?

Изменить: Я пытаюсь разработать тест, очищающий модуль ядра от строки кэша или всего процесса (с помощью wbinvd()). Программа работает от имени root, но я предпочел бы оставаться в пространстве пользователя, если это возможно.

Ответ 1

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

Эта программа работает в моем окне 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 of /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;
}

Ответ 2

Я не знаю какой-либо общей команды, чтобы получить состояние кэша, но есть способы:

  • Я думаю, это проще всего: если вы получили свой модуль ядра, просто разоберите его и посмотрите команды кэширования недействительности/очистки (только мне пришло в голову 3: WBINDVD, CLFLUSH, INVD).
  • Вы только что сказали, что это для i386, но я думаю, вы не имеете в виду 80386. Проблема в том, что существует много разных вариантов расширения и функций. Например. новейшая серия Intel имеет некоторые регистры производительности/профилирования для включенной системы кэширования, которые вы можете использовать для оценки промахов/ударов кеша/количества передач и тому подобного.
  • Аналогично 2, очень в зависимости от системы, которую вы получили. Но когда у вас есть многопроцессорная конфигурация, вы можете смотреть первый протокол когерентности кэша (MESI) со вторым.

Вы упомянули WBINVD - afaik, который всегда будет завершен, т.е. все строки кэша

Ответ 3

Это может быть не ответ на ваш конкретный вопрос, но вы пробовали использовать профилировщик кеша, например Cachegrind? Он может использоваться только для профилирования кода пользовательского пространства, но вы, возможно, сможете использовать его, тем не менее, например. перемещение кода вашей функции в пользовательское пространство, если оно не зависит от каких-либо интерфейсов, специфичных для ядра.

На самом деле это может быть более эффективным, чем попытка запросить у процессора информацию, которая может или не может существовать, и на нее, вероятно, повлияет ваше простое задание - да, Heisenberg был до его времени: -)