Доступ к некэшируемой области с помощью mmap и /proc/mtrr

Я играю с mmap и /proc/mtrr, пытаясь провести углубленный анализ физической памяти. Вот основная идея того, что я пытаюсь сделать, и краткое изложение того, что я сделал до сих пор. У меня версия ядра Ubuntu 3.5.0-54-универсальная.

В основном я сопоставляю определенный физический адрес (используя подсказки из /proc/iomem) и измеряю задержку доступа к этому диапазону физических адресов. Вот что я сделал до сих пор:

  1. Создал запись в /proc/mtrr, чтобы сделать диапазон физических адресов, который я буду отображать, некэшируемым.
  2. 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

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

Хотя у меня нет проблем с запуском кода, у меня есть следующие проблемы:

  1. Правильно ли выбрать этот конкретный диапазон физических адресов, обозначенный как системная оперативная память, для чтения/записи? Насколько я понимаю, этот диапазон адресов используется для хранения данных и кода. Кроме того, при чтении /dev/mem с помощью hexdump я заметил, что адресная область не инициализирована (установлена ​​на 0).
  2. Чтобы проверить, действительно ли обращения к некэшируемой области не кешируются, я выполняю perf stat -e cache-misses:u, чтобы измерить количество промахов кеша. Я получаю число в диапазоне 128 200. Для меня это подтверждает, что адреса не кешируются и попадают в ОЗУ, как в цикле, я делаю (8192/64)*500*2 = 128 000 обращений. Я проделал то же упражнение с другим подобным фрагментом кода, заменив mmap динамическим выделением памяти из массива символов той же длины. В этом случае статистика производительности сообщила о гораздо меньшем количестве промахов кеша.
  3. Чтобы еще раз проверить, действительно ли я обхожу кеш и обращаюсь к памяти, я изменяю смещение на другое значение в пределах диапазона системной ОЗУ (скажем, 0x80000) и запускаю команду perf, чтобы измерить количество промахов кеша. Путаница здесь в том, что он сообщает почти такое же количество промахов кэша, что и в предыдущем случае (около 128 200). Я бы ожидал чего-то гораздо меньшего, поскольку я не сделал эту область физического адреса некэшируемой.

Любые предложения/отзывы по этому поводу, чтобы понять это наблюдение, будут полезны.

Спасибо


person Anirudh Kaushik    schedule 09.11.2014    source источник
comment
Кто-нибудь может помочь? Действительно любопытно узнать, почему это наблюдение? Спасибо.   -  person Anirudh Kaushik    schedule 16.11.2014


Ответы (1)


Думаю, я понял это. MAP_PRIVATE из справочных страниц говорит, что изменения не отражаются в базовом файле. При изменении его на MAP_SHARED и включении записи в /proc/mtrr изменение количества промахов и попаданий в кэш значительно меняется.

person Anirudh Kaushik    schedule 24.11.2014