it-roy-ru.com

Как узнать размер строки кэша L1 с помощью IO измерения времени?

В качестве школьного задания мне нужно найти способ получить размер строки кэша данных L1 без чтения файлов конфигурации или использования вызовов API. Предполагается использовать тайминги доступа к памяти для анализа и получения этой информации. Так как я могу это сделать? 

В неполной попытке выполнить другую часть задания, чтобы найти уровни и размер кэша, я имею: 

for (i = 0; i < steps; i++) {
    arr[(i * 4) & lengthMod]++;
}

Я думал, может быть, мне просто нужно изменить строку 2, часть (i * 4)? Поэтому, когда я превышаю размер строки кэша, мне может понадобиться заменить его, что займет какое-то время? Но так ли это просто? Требуемый блок уже может быть где-то в памяти? Или, возможно, я все еще могу рассчитывать на то, что, если у меня будет достаточно большой steps, он все равно будет работать достаточно точно? 

ОБНОВЛЕНИЕ

Вот покушение на GitHub ... Основная часть ниже

// repeatedly access/modify data, varying the STRIDE
for (int s = 4; s <= MAX_STRIDE/sizeof(int); s*=2) {
    start = wall_clock_time();
    for (unsigned int k = 0; k < REPS; k++) {
        data[(k * s) & lengthMod]++;
    }
    end = wall_clock_time();
    timeTaken = ((float)(end - start))/1000000000;
    printf("%d, %1.2f \n", s * sizeof(int), timeTaken);
}

Проблема в том, что между сроками нет большой разницы. FYI. так как для кеша L1. У меня есть размер = 32 K (размер массива)

36
Jiew Meng

Выделите БОЛЬШОЙ массив char (убедитесь, что он слишком большой, чтобы поместиться в кэш L1 или L2). Заполните его случайными данными.

Начните ходить по массиву с шагом n байтов. Сделайте что-нибудь с найденными байтами, например, суммируйте их.

Оцените и рассчитайте, сколько байтов в секунду вы можете обработать с различными значениями n, начиная с 1 и считая до 1000 или около того. Убедитесь, что ваш бенчмарк выводит вычисленную сумму, чтобы компилятор не мог оптимизировать код, измеренный в бенчмарках.

Когда n == размер строки вашего кэша, каждый доступ потребует чтения новой строки в кэш L1. Таким образом, результаты тестов должны стать довольно резкими в этой точке.

Если массив достаточно большой, к тому времени, как вы достигнете конца, данные в начале массива уже будут уже вне кеша, что вам и нужно. Поэтому после увеличения n и повторного запуска на результаты не повлияет наличие необходимых данных в кэше.

27
Alex D

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

Идея, лежащая в основе нашего инструмента для калибровки, заключается в том, чтобы иметь микро-эталон, производительность которого зависит только от на частоте пропусков кэша, которые происходят. Наш калибратор представляет собой простую программу на C, в основном небольшую петлю который выполняет миллион операций чтения из памяти. Изменяя шаг (то есть смещение между двумя последующими Обращениями к памяти) и размер области памяти, мы принудительно изменяем частоту пропадания кэша.

В принципе, вероятность пропуска кеша определяется размером массива. Размеры массива, которые соответствуют кэш L1 не генерирует никаких кеш-ошибок после загрузки данных в кеш. Аналогично, массивы, которые превышают размер кэша L1, но все еще вписываются в L2, вызовут пропуски L1, но не пропустят L2. В заключение, массивы, большие чем L2, вызывают как пропуски L1, так и L2.

Частота пропусков кеша зависит от шага доступа и размера строки кеша. С успехами равный или превышающий размер строки кэша, при каждой итерации происходит потеря кэша. С успехами меньше, чем размер строки кэша, потеря кэша происходит только каждые n итераций (в среднем), где n равно коэффициент кеша линия размер/шаг.

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

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

Мне пришлось закомментировать #include "math.h", чтобы он скомпилировался, после чего он правильно нашел значения кэша моего ноутбука. Я также не мог просматривать сгенерированные файлы postscript.

5
auselen

Вы можете использовать функцию CPUID в ассемблере, хотя и не переносимая, она даст вам то, что вы хотите.

Для микропроцессоров Intel размер строки кэша можно рассчитать, умножив bh на 8 после вызова функции cpuid 0x1.

Для микропроцессоров AMD размер строки кэша данных находится в cl, а инструкция Размер строки кэша - в dl после вызова функции cpuid 0x80000005.

Я взял это из этой статьи здесь .

3
Tony The Lion

Я думаю, что вы должны написать программу, которая будет проходить через массив в случайном порядке, а не прямо, потому что современный процесс выполняет аппаратную предварительную выборку . Например, создайте массив int, значения которого будут равны числу следующей ячейки . Я сделал аналогично программа 1 год назад http://Pastebin.com/9mFScs9Z Извините за мой английский, я не являюсь носителем языка.

2
Alexey Matveev

Посмотрите, как в memtest86 реализовано. Они измеряют и анализируют скорость передачи данных в некотором роде. Точки изменения скорости соответствуют размеру L1, L2 и возможному размеру кэша L3.

1
vitaly.v.ch

Если вы застряли в грязи и не можете выбраться, посмотрите здесь .

Есть руководства и код, который объясняет, как делать то, что вы просите. Код тоже довольно качественный. Посмотрите на "Библиотека подпрограмм".

Код и руководства основаны на процессорах X86.

1
JimR

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

Я бы просто прочитал кучу байтов, не печатая их (печать так плохо работала, что становилась узким местом). Во время чтения время должно быть прямо пропорционально количеству прочитанных байтов, пока данные больше не смогут соответствовать L1, тогда вы получите снижение производительности.

Вы должны также выделить память один раз в начале программы и перед началом отсчета времени.

0
enTropy

Просто записка.

Размер строки кэша является переменным в нескольких ARM семействах Cortex и может изменяться во время выполнения без каких-либо уведомлений для текущей программы.

0
vitaly.v.ch