我正在使用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个线程,这些线程通过调用 loop 函数从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数据线替换看起来L1D.REPLACEMENT似乎很有意义,但我不认为L1D.REPLACEMENT在启用时也算预取。
仅在此特定情况下,我不理解MEM_LOAD_RETIRED.L1_MISS计数器看不到main中由读取操作引起的事件的原因是什么。例如,如果来自NUMA2的线程(而不是读取线程)修改数组元素,则对于同一循环,我会得到L1_MISS:99818。因此,任何建议都将有所帮助。 我试图提供代码的主要框架。如果评论点的任何部分很重要,我也可以添加它们。