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

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

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


person Roman A. Taycher    schedule 18.05.2011    source источник
comment
Вы имеете в виду кеш процессора? А сколько точно времени недавно?   -  person Gunther Piez    schedule 18.05.2011
comment
Намного меньше секунды (я знаю, что это не очень точно). В основном я хочу проверить, очищала ли кеш довольно быстрая функция.   -  person Roman A. Taycher    schedule 18.05.2011
comment
Вопрос не имеет смысла: (а) обычно существует несколько кешей, (б) строки кеша все время вытесняются, (в) очистка кеша (т. е. вытеснение всех строк кеша) обычно не происходит, (d ) в общем случае ЦП ничего не знает о том, что происходит в любом из кешей   -  person Paul R    schedule 18.05.2011
comment
Это может быть необычно, но промывка - это то, что делается в некоторых местах, нет?   -  person Roman A. Taycher    schedule 18.05.2011
comment
@Roman: да, WBINVD сбрасывает все кеши данных (неясно, сбрасывал ли он также кеш инструкций L1, и его реализация зависит от ЦП), но использовать эту инструкцию довольно необычно (самоизменяющийся код - единственный пример что приходит на ум) и даже в этом случае кеши немедленно начнут снова заполняться, и ЦП не имеет прямых сведений о текущем состоянии любого из кешей. Вы должны объяснить, чего вы на самом деле пытаетесь достичь, то есть мотивацию вашего вопроса.   -  person Paul R    schedule 18.05.2011
comment
очищает ли кэш низкоуровневая схема при определенных обстоятельствах.   -  person Roman A. Taycher    schedule 18.05.2011
comment
Показывает ли opcontrol --list-events какое-нибудь интересное событие?   -  person ninjalj    schedule 02.07.2011


Ответы (3)


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

Эта программа работает на моей машине 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;
}
person Ben Jackson    schedule 05.07.2011
comment
Спасибо, сначала это выглядело хорошо, но оказалось слишком неточным. возможно из-за проблем в моем коде. - person Roman A. Taycher; 27.07.2011
comment
@Ben Есть ли какие-либо особые требования (компиляция, системные настройки и т. д.), которые необходимо выполнить, чтобы этот код работал? Я получаю в строке flush: тики того же порядка, что и кэшированные обращения. Я использую macOS 10.15.5 с gcc-9 и clang 11 (оба протестированы). - person Patrick; 19.06.2020

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

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

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

person flolo    schedule 02.07.2011
comment
У меня есть исходный код, я пытаюсь написать тест, чтобы подтвердить, что происходит при определенных условиях. Атом как двухъядерный, так и одноядерный. - person Roman A. Taycher; 03.07.2011
comment
Если у вас есть исходный код, не могли бы вы просто просмотреть его, чтобы проверить, выдается ли инструкция WBINVD? - person jalf; 07.07.2011
comment
+1 за идеи для ПК. Счетчики производительности могут предоставить информацию, которую запрашивает вопрос. - person TheBlastOne; 08.07.2011
comment
jalf: 1) Я пытаюсь провести полуавтоматическое тестирование, а не проверку кода (и код может измениться, надеюсь, тест все еще будет работать). 2) WBINVD вызывается в некоторых местах в зависимости от политики. Я пытаюсь проверить различные условия, чтобы увидеть, вызывается ли он. - person Roman A. Taycher; 08.07.2011

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

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

person thkala    schedule 07.07.2011