每个mmap/access/munmap有两个TLB-miss

Moh*_*ati 8 c performance performancecounter tlb perf

for (int i = 0; i < 100000; ++i) {
    int *page = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
                            MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);

    page[0] = 0;

    munmap(page, PAGE_SIZE);
}
Run Code Online (Sandbox Code Playgroud)

我期望在用户空间中获得~100000 dTLB-store-miss,每次迭代一次(同样~100000页错误和内核的dTLB-load-miss).运行以下命令,结果大约是我期望的2倍.如果有人能澄清为什么会这样,我将不胜感激:

perf stat -e dTLB-store-misses:u ./test
Performance counter stats for './test':

           200,114      dTLB-store-misses

       0.213379649 seconds time elapsed
Run Code Online (Sandbox Code Playgroud)

PS我已经验证并确定生成的代码没有引入任何可以证明这个结果的东西.此外,我确实得到~100000页错误和dTLB加载未命中:k.

Bre*_*dan 7

我期望在用户空间中获得~100000 dTLB-store-miss,每次迭代一次

我希望如此:

  • CPU尝试做page[0] = 0;,尝试加载包含的缓存行page[0],找不到它的TLB条目,递增dTLB-load-misses,取出转换,实现页面"不存在",然后生成页面错误.
  • 页面错误处理程序分配页面并(因为页面表已被修改)确保TLB条目无效(可能依赖于英特尔CPU不会缓存"不存在"页面的事实,不一定是通过显式执行INVLPG) .页面错误处理程序返回到导致错误的指令,以便可以重试它.
  • CPU尝试再次尝试page[0] = 0;,尝试加载包含的缓存行page[0],找不到它的TLB条目,递增dTLB-load-misses,获取转换,然后修改缓存行.

为了好玩,您可以使用MAP_POPULATE标志mmap()来尝试让内核预先分配页面(并避免页面错误和第一次TLB未命中).