В качестве школьного задания мне нужно найти способ получить размер строки кэша данных L1 без чтения файлов конфигурации или использования вызовов API. Предполагается использовать время доступа к памяти для чтения / записи для анализа & получить эту информацию Так как я могу это сделать?
В неполной попытке попробуйте другую часть задания, чтобы найти уровни & Размер кеша у меня есть:
for (i = 0; i < steps; i++) {
arr[(i * 4) & lengthMod]++;
}
Я думал, может быть, мне просто нужно изменить строку 2, (i * 4)
часть? Поэтому, когда я превышаю размер строки кэша, мне может понадобиться заменить его, что займет какое-то время? Но так ли это просто? Требуемый блок уже может быть где-то в памяти? Или Perpahs я все еще могу рассчитывать на то, что, если у меня есть достаточно большой 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 (размер массива)
Выделите БОЛЬШОЙ char
массив (убедитесь, что он слишком большой, чтобы поместиться в L1 или же L2 кеш). Заполните его случайными данными.
Начните ходить по массиву в несколько шагов n
байт. Сделайте что-нибудь с найденными байтами, например, суммируйте их.
Оцените и рассчитайте, сколько байт / секунду вы можете обработать с различными значениями n
, начиная с 1 и считая до 1000 или около того. Убедитесь, что ваш бенчмарк выводит вычисленную сумму, чтобы компилятор не мог оптимизировать код, измеренный в бенчмарках.
когда n
== размер строки вашего кеша, каждый доступ потребует чтения новой строки в кэш L1. Таким образом, результаты тестов должны стать довольно резкими в этой точке.
Если массив достаточно большой, к тому времени, как вы достигнете конца, данные в начале массива уже будут уже вне кеша, что вам и нужно. Так что после того, как вы увеличиваете n
и начните заново, на результаты не повлияет наличие необходимых данных в кеше.
Посмотри на калибратор, Все работы защищены авторским правом, но исходный код находится в свободном доступе. Из своего документ Идея вычисления размеров строк кэша звучит гораздо более обоснованно, чем то, что здесь уже сказано.
Идея, лежащая в основе нашего калибратора, заключается в том, чтобы иметь микро-эталон, производительность которого зависит только
на частоте пропусков кэша, которые происходят. Наш калибратор представляет собой простую программу на C, в основном небольшую петлю
который выполняет миллион операций чтения из памяти. Изменяя шаг (т.е. смещение между двумя последующими
доступ к памяти) и размер области памяти, мы принудительно меняем частоту пропусков кэша.В принципе, вероятность пропуска кеша определяется размером массива. Размеры массива, которые вписываются в
кэш L1 не генерирует никаких кеш-ошибок после загрузки данных в кеш. Аналогично,
массивы, которые превышают размер кэша L1, но все еще вписываются в L2, вызовут пропуски L1, но не пропустят L2. В заключение,
массивы, большие чем L2, вызывают как пропуски L1, так и L2.Частота пропусков кеша зависит от шага доступа и размера строки кеша. С успехами
равный или превышающий размер строки кэша, при каждой итерации происходит потеря кэша. С успехами
меньше, чем размер строки кэша, потеря кэша происходит только каждые n итераций (в среднем), где n
коэффициент кеша
линия
размер / шаг.Таким образом, мы можем рассчитать задержку при отсутствии кэша, сравнивая время выполнения без
пропускает время выполнения с ровно одним промахом за итерацию. Этот подход работает, только если
доступ к памяти выполняется исключительно последовательно, т. е. мы должны убедиться, что ни две, ни более не загружаются
инструкции, ни доступ к памяти, ни чистая работа процессора могут перекрываться. Мы используем простую погоню указателя
Механизм для достижения этого: область памяти, к которой мы обращаемся, инициализируется так, что каждая загрузка возвращает
адрес для последующей загрузки в следующей итерации. Таким образом, суперскалярные процессоры не могут извлечь выгоду из
их способность скрывать задержку доступа к памяти путем умозрительного выполнения.Чтобы измерить характеристики кэша, мы проводим наш эксперимент несколько раз, изменяя шаг и
размер массива. Мы гарантируем, что шаг изменяется, по крайней мере, между 4 байтами и в два раза максимальным
ожидаемый размер строки кэша, и что размер массива изменяется от половины минимального ожидаемого размера кэша до
по крайней мере в десять раз превышает максимальный ожидаемый размер кэша.
Я должен был закомментировать #include "math.h"
чтобы скомпилировать его, после этого он правильно нашел значения кэша моего ноутбука. Я также не мог просматривать сгенерированные файлы postscript.
Вы можете использовать CPUID
Функция в ассемблере, хотя и не переносимая, она даст вам то, что вы хотите.
Для микропроцессоров Intel размер строки кэша можно рассчитать, умножив bh на 8 после вызова функции cpuid 0x1.
Для микропроцессоров AMD размер строки кэша данных находится в cl, а инструкция Размер строки кэша — в dl после вызова функции cpuid 0x80000005.
Я взял это из этого статья здесь.
Я думаю, что вы должны написать программу, которая будет проходить через массив в случайном порядке, а не прямо, потому что современные процессы делают аппаратную предварительную выборку.
Например, сделать массив int, значения которого будут номером следующей ячейки.
Я сделал подобную программу 1 год назад http://pastebin.com/9mFScs9Z
Извините за мой английский, я не являюсь носителем языка.
Посмотрите, как в memtest86 реализовано. Они измеряют и анализируют скорость передачи данных в некотором роде. Точки изменения скорости соответствуют размеру L1, L2 и возможному размеру кэша L3.
Если вы застряли в грязи и не можете выйти, посмотрите Вот.
Есть руководства и код, который объясняет, как делать то, что вы просите. Код тоже довольно качественный. Посмотрите на «Библиотека подпрограмм».
Код и руководства основаны на процессорах X86.
Я думаю, этого должно быть достаточно для определения времени операции, которая использует некоторое количество памяти. Затем постепенно увеличивайте память (например, операнды), используемую операцией.
Когда производительность операции резко снижается, вы нашли предел.
Я бы просто прочитал кучу байтов, не печатая их (печать так плохо работала, что становилась узким местом). Во время чтения время должно быть прямо пропорционально количеству прочитанных байтов, пока данные больше не смогут соответствовать L1, тогда вы получите снижение производительности.
Вы должны также выделить память один раз в начале программы и перед началом отсчета времени.
Просто записка.
Размер строки кэша является переменным на нескольких семействах ARM Cortex и может изменяться во время выполнения без каких-либо уведомлений для текущей программы.