c - x86 上的简单 PAPI 分析中意外出现大量 TLB 未命中

标签 c x86 tlb papi nehalem

我正在使用 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]);

我预计打印的数字在 32 左右,或者至少是某个倍数,但始终得到 93 或以上的结果(并非始终高于 96,即每次迭代不只是 3 个缺失)。我正在运行,固定在一个核心上,没有其他任何东西(除了定时器中断)。

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

最佳答案

根据评论:

  • 如果使用 malloc(),大约会丢失 90 次。
  • 如果使用 calloc() 或事先迭代数组,则会丢失 32 次。

原因是由于延迟分配。在您触摸操作系统之前,操作系统实际上并没有为您提供内存。

当您第一次触摸该页面时,将会导致页面错误。操作系统将捕获此页面错误并动态正确分配它(which involves zeroing等等)。这就是导致所有额外 TLB 未命中的开销。

但是,如果您使用 calloc() 或提前触及所有内存,则会将此开销移至启动计数器之前。因此结果较小。

至于剩下的32次未命中……我不知道。
(或者正如评论中提到的,这可能是 PAPI 干扰。)

关于c - x86 上的简单 PAPI 分析中意外出现大量 TLB 未命中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14960116/

相关文章:

x86 - 从内存读取/写入数据的 x86 指令如何与 L1 和 L2 缓存交互?

mysql - cakephp在不同主机上的解释

c - 在 64 位中将地址空间大小保持为 4 GB

x86 - 英特尔处理器的 TLB ASID 标签中有多少位?以及如何处理 'ASID overflow' ?

c - C 中的字符串和字符串函数

C:在结构元素上使用 Free() 时出现问题,行为奇怪

c - 处理数组中的 free 的简单方法

c - 与结构内仅一个成员进行 union 的目的

c - 尝试刷新缓存时出现段错误(核心转储)错误

assembly - 写入翻译后备缓冲区