使用mmap和/ proc / mtrr访问不​​可访问的区域

时间:2014-11-09 05:50:12

标签: c linux memory mmap perf

我正在玩mmap和/ proc / mtrr,以便对物理内存分析进行深入分析。这是我想要做的基本想法,以及到目前为止我所做的总结。我在Ubuntu内核版本3.5.0-54-generic。

我基本上正在映射到特定的物理地址(使用/ proc / iomem中的提示)并测量此物理地址范围的访问延迟。以下是我到目前为止所做的事情:

  1. 在/ proc / mtrr中创建了一个条目,以使我将要映射的物理地址范围无法访问。
  2. 使用/ dev / mem mmaped到特定地址。我不得不放松安全限制,以便从/ dev / mem读取超过1 MB的空间。
  3. 虽然,我能够毫无问题地执行该程序,但我对于无法访问的部分是否真正有效存在疑问。这是我正在使用的代码片段。请注意,我使用了先前研究论文中的伪代码来创建此代码。

      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;
    }
    

    我使用基于输出/ proc / iomem的偏移量0x20000,如下所示(仅显示相关信息):

    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. 选择表示为系统RAM的特定物理地址范围来进行读/写操作是否正确?我的理解是该地址范围用于存储数据和代码。除了使用hexdump读取/ dev / mem之外,我发现地址区域是未初始化的(设置为0)。
    2. 要检查对未缓存区域的访问是否实际未缓存,我会执行perf stat -e cache-miss:u来测量发生的缓存未命中数。我得到的数字在128,200之间。对我来说这证实了地址没有被缓存并且像循环一样进入RAM,我正在做(8192/64)* 500 * 2 = 128,000次访问。我使用另一个类似的代码进行了相同的perf练习,mmap替换为相同长度的字符数组的动态内存分配。在这种情况下,perf stat报告了更少的缓存未命中。
    3. 要重新检查我是否确实绕过缓存并转到内存,我将偏移量更改为系统RAM范围内的另一个值(例如0x80000)并运行perf命令来测量发生的缓存未命中数。这里的混乱是它报告了前一种情况下大约相同数量的缓存未命中(大约128,200)。我期望更少的东西,因为我没有使该物理地址区域无法访问。
    4. 对此有任何建议/反馈以理解这一观察结果会有所帮助。

      由于

1 个答案:

答案 0 :(得分:1)

我想我明白了。手册页中的MAP_PRIVATE表示更改未反映到基础文件中。在将其更改为MAP_SHARED并启用/ proc / mtrr中的条目时,缓存未命中数和命中数的变化会发生显着变化。