Я играю с mmap и /proc/mtrr, пытаясь провести углубленный анализ физической памяти. Вот основная идея того, что я пытаюсь сделать, и краткое изложение того, что я сделал до сих пор. У меня версия ядра Ubuntu 3.5.0-54-универсальная.
В основном я сопоставляю определенный физический адрес (используя подсказки из /proc/iomem) и измеряю задержку доступа к этому диапазону физических адресов. Вот что я сделал до сих пор:
- Создал запись в /proc/mtrr, чтобы сделать диапазон физических адресов, который я буду отображать, некэшируемым.
- mmaped на конкретный адрес с помощью /dev/mem. Мне пришлось ослабить ограничения безопасности, чтобы прочитать более 1 МБ из /dev/mem.
Хотя я могу выполнить программу без проблем, у меня есть некоторые сомнения относительно того, действительно ли работает некэшируемая часть. Вот фрагмент кода, который я использую. Обратите внимание, что для создания этого кода я использовал псевдокод из предыдущей исследовательской работы.
int main(int argc, char *argv[]) {
int fd; // file descriptor to open /dev/mem
struct timespec time1, time2;
fd = open("/dev/mem", O_RDWR|O_SYNC);
if (fd == -1) {
printf("\n Error opening /dev/mem");
return 0;
}
struct timespec t1, t2;
char *addr = (char*)mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0x20000);
if (addr == MAP_FAILED) {
printf("\n mmap() failed");
}
// Begin accessing
char *addr1 = addr;
char *addr2 = addr1 + 64; // add cache line
unsigned int i = 0;
unsigned int j = 0;
// Begin accessing uncached region
while(j < 8192){
i = 0;
while(i < 500) {
*addr1 = *addr2 + i;
*addr2 = *addr1 + i;
i = i+1;
}
j = j + 64;
addr2 = addr1 + j;
}
if (munmap(addr, 8192) == -1) {
printf("\n Unmapping failed");
return 0;
}
printf("\n Success......");
return 0;
}
Я использую смещение 0x20000 на основе вывода /proc/iomem, как показано ниже (показывая только необходимую информацию):
00000000-0000ffff : reserved
**00010000-0009e3ff : System RAM**
0009e400-0009ffff : RAM buffer
000a0000-000bffff : PCI Bus 0000:00
000a0000-000b0000 : PCI Bus 0000:20
000c0000-000effff : PCI Bus 0000:00
Ниже приведены записи в /proc/mtrr:
reg00: base=0x0d3f00000 ( 3391MB), size= 1MB, count=1: uncachable
reg01: base=0x0d4000000 ( 3392MB), size= 64MB, count=1: uncachable
reg02: base=0x0d8000000 ( 3456MB), size= 128MB, count=1: uncachable
reg03: base=0x0e0000000 ( 3584MB), size= 512MB, count=1: uncachable
reg04: base=0x000020000 ( 0MB), size= 8KB, count=1: uncachable
Как видите, последняя запись делает интересующую область адреса некэшируемой.
Хотя у меня нет проблем с запуском кода, у меня есть следующие проблемы:
- Правильно ли выбрать этот конкретный диапазон физических адресов, обозначенный как системная оперативная память, для чтения/записи? Насколько я понимаю, этот диапазон адресов используется для хранения данных и кода. Кроме того, при чтении /dev/mem с помощью hexdump я заметил, что адресная область не инициализирована (установлена на 0).
- Чтобы проверить, действительно ли обращения к некэшируемой области не кешируются, я выполняю perf stat -e cache-misses:u, чтобы измерить количество промахов кеша. Я получаю число в диапазоне 128 200. Для меня это подтверждает, что адреса не кешируются и попадают в ОЗУ, как в цикле, я делаю (8192/64)*500*2 = 128 000 обращений. Я проделал то же упражнение с другим подобным фрагментом кода, заменив mmap динамическим выделением памяти из массива символов той же длины. В этом случае статистика производительности сообщила о гораздо меньшем количестве промахов кеша.
- Чтобы еще раз проверить, действительно ли я обхожу кеш и обращаюсь к памяти, я изменяю смещение на другое значение в пределах диапазона системной ОЗУ (скажем, 0x80000) и запускаю команду perf, чтобы измерить количество промахов кеша. Путаница здесь в том, что он сообщает почти такое же количество промахов кэша, что и в предыдущем случае (около 128 200). Я бы ожидал чего-то гораздо меньшего, поскольку я не сделал эту область физического адреса некэшируемой.
Любые предложения/отзывы по этому поводу, чтобы понять это наблюдение, будут полезны.
Спасибо