在x86上简单的PAPI分析中出现了大量的TLB未命中

jme*_*lfe 2 c x86 tlb nehalem papi

我正在使用PAPI高级API检查循环通过数组的简单程序中的TLB未命中,但看到的数字大于预期.

在其他简单的测试用例中,结果似乎非常合理,这使我认为结果是真实的,额外的遗漏是由硬件预取或类似的.

任何人都可以解释这些数字或指出我使用PAPI时出现的错误吗?

int events[] = {PAPI_TLB_TL};
long long values[1];
char * databuf = (char *) malloc(4096 * 32);

if (PAPI_start_counters(events, 1) != PAPI_OK) exit(-1);
if (PAPI_read_counters(values, 1) != PAPI_OK) exit(-1); //Zeros the counters

for(int i=0; i < 32; ++i){
    databuf[4096 * i] = 'a';
}

if (PAPI_read_counters(values, 1) != PAPI_OK) exit(-1); //Extracts the counters

printf("%llu\n", values[0]);
Run Code Online (Sandbox Code Playgroud)

我期望打印的数字在32或至少一些倍数的区域内,但始终得到93或更高的结果(不是始终高于96,即每次迭代不仅仅是3次未命中).我正在运行固定到核心,没有别的东西(除了计时器中断).

我在Nehalem并没有使用大页面,因此DTLB中有64个条目(L2中为512个).

Mys*_*ial 5

根据评论:

  • 如果malloc()使用约90次未命中.
  • 如果calloc()使用了32次未命中,或者如果数组是在手前迭代的话.

原因是懒惰分配.在触摸它之前,操作系统实际上并没有给你内存.

首次触摸该页面时,将导致页面错误.操作系统将捕获此页面错误并在运行中正确分配它(其中涉及归零).这是导致所有额外TLB未命中的开销.

但是,如果您使用calloc()或提前触摸所有内存,则开始计数器之前将此开销移至此处.因此结果较小.

至于剩下的32个未命中......我不知道.
(或者在评论中提到,它可能是PAPI的干扰.)