1

我正在使用 PAPI 来计算 L1 缓存访问结果。大多数原生事件都会给出预期的结果,但是有一种情况是 L1_MISS 不精确。我有一个大小为 64 的对象和 100,000 个元素的易失性数组,如代码所示:

typedef struct _object{
  int value;
  char pad[60];
} object;

#define arr_size 100000
volatile object  array [arr_size];

void * loop (int arg){
  /* Threads are set in NUMA2 */
  int temp;
  for(int i=0; i < arr_size; i++){
    temp = array[i].value;
  }
}

我正在使用两个 NUMA 节点在 Skylake 处理器中进行测试。我禁用了预取器。使用 gcc -O3 编译。场景如下:从 NUMA1 中设置的主进程,我初始化一个数组并刷新缓存行。然后我创建 5 个线程,通过调用循环函数从 NUMA2 读取相同的数组。在所有这些都终止后,我从主进程循环遍历一个数组,读取每个元素并监控 L1 缓存访问结果:

int main(int argc, char* argv[]){
    /* Main thread is set in NUMA1 */
    /* Array is initialized and flushed from the cache*/
    /* 5 threads are created with pthread_create, that call loop function, 
       and waited to finish by calling pthread_join*/

 int tmp;
 /*Hardware counters are counted for this loop*/ 
 for(int i=0; i < arr_size; i++){
    tmp = array[i].value;
 }
}

我正在阅读这 5 个本机事件计数器:

MEM_INST_RETIRED.ALL_LOADS: 100095
L1D.REPLACEMENT: 100246 
MEM_LOAD_RETIRED.L1_HIT: 113 
MEM_LOAD_RETIRED.L1_MISS: 56 
MEM_LOAD_RETIRED.FB_HIT: 55 

期望看到 L1_MISS 大约为 100,000,因为未在缓存中获取元素,而 main 中的此读取会导致未命中。ALL_LOADS 也不等于三个计数器的总和:L1_HIT + L1_MISS + FB_HIT。尽管 L1D.REPLACEMENT 在这种情况下通过计算 L1D 数据线替换似乎是有意义的,但我不相信它,因为它在启用时也计算预取。

我不明白 MEM_LOAD_RETIRED.L1_MISS 计数器没有看到由 main 中的读取操作引起的事件的原因是什么,仅在这种特定情况下。例如,如果来自 NUMA2 的线程不是读取,而是修改一个数组元素,那么对于同一个循环,我会得到 L1_MISS:99818。所以任何建议都会有所帮助。我试图提供代码的主要框架。如果评论点的任何部分很重要,我也可以添加它们。

4

0 回答 0