Я использую библиотеку PAPI для чтения аппаратных счетчиков. Я заметил, что порядок вызова инициализации PAPI_library_init (PAPI_VER_CURRENT) влияет на результаты, которые я получаю. Моя инициализация и чтение массива выглядит так:
int retval;
/*
retval = PAPI_library_init(PAPI_VER_CURRENT);
if (retval != PAPI_VER_CURRENT) {
fprintf(stderr, "PAPI library init error!\n");
exit(1);
}
*/
for(int i=0; i < arr_size; i++){
array[i].value = 1;
//_mm_clflush(&array[i]); flushing does not make difference.
}
_mm_mfence();
for(int i=0; i < arr_size; i++){
temp = array[i].value ;
}
_mm_mfence();
retval = PAPI_library_init(PAPI_VER_CURRENT);
if (retval != PAPI_VER_CURRENT) {
fprintf(stderr, "PAPI library init error!\n");
exit(1);
}
Необходимость второго цикла для чтения массива для протокола согласованности, я считаю, но здесь это не должно иметь большого значения. После этого я добавляю собственные события MEM_LOAD_RETIRED в набор событий, который я хочу прочитать, и использую PAPI_read вокруг этого третьего цикла (я читаю его до и после цикла и в конце выводю разницу):
for(int i=0; i < arr_size; i++){
temp = array[i].value ;
}
где arr_size равен 1000, а каждый элемент массива имеет размер 64 байта (равен строке кэша). Я отключил всех предварительных сборщиков. Я компилирую с флагом gcc -O3 для оптимизации и библиотекой -lpapi. с этим кодом для третьего цикла я получаю:
L1_HIT: 64, L1_MISS: 1011, L2_HIT: 15, L2_MISS: 996.
Однако, если я раскомментирую PAPI_library_init до инициализации массива и прокомментирую его после этого, я получу следующие результаты:
L1_HIT: 73, L1_MISS: 1004, L2_HIT: 990, L2_MISS: 14.
Я тестирую это на сервере Skylake, размеры кэша:
L1d cache: 32K
L1i cache: 32K
L2 cache: 1024K
L3 cache: 22528K
Теперь я немного сбит с толку, почему инициализация папы влияет на эти результаты. это L2 ударил и пропустил это изменение. Все, что мне нужно, это третий цикл, и, как я полагаю, влияние первых двух циклов на счетчики не учитывается.
Таким образом, любая подсказка для этого была бы полезна, поскольку вся документация гласит: «PAPI_library_init () инициализирует библиотеку PAPI. Она должна быть вызвана перед использованием любых функций PAPI низкого уровня. Если ваше приложение использует потоки PAPI_thread_init (3) также следует вызывать перед выполнением любых вызовов в библиотеку, кроме PAPI_library_init (). "