1

我正在使用 PAPI 库来读取硬件计数器。我注意到调用 PAPI_library_init(PAPI_VER_CURRENT) 初始化的顺序对我得到的结果有影响。我对数组的初始化和读取是这样的:

int retval;

/*
     retval = PAPI_library_init(PAPI_VER_CURRENT);

     if (retval != PAPI_VER_CURRENT) {
       fprintf(stderr, "PAPI library init error!\n");
       exit(1);
     }
*/

      for(int i=0; i < arr_size; i++){
        array[i].value = 1;
        //_mm_clflush(&array[i]); flushing does not make difference. 
      }
      _mm_mfence();


      for(int i=0; i < arr_size; i++){
        temp = array[i].value ;
      }
      _mm_mfence();



      retval = PAPI_library_init(PAPI_VER_CURRENT);

      if (retval != PAPI_VER_CURRENT) {
        fprintf(stderr, "PAPI library init error!\n");
        exit(1);
      }

我相信第二个循环读取数组的必要性是为了一致性协议,但在这里应该没什么大不了的。在此之后,我将 MEM_LOAD_RETIRED 的本机事件添加到要读取的事件集中,并在第三个循环周围使用 PAPI_read(我在循环之前和之后读取它,最后打印差异):

for(int i=0; i < arr_size; i++){
       temp = array[i].value ;
     } 

其中 arr_size 为 1000,数组的每个元素为 64 字节大小(等于缓存行)。我已禁用所有预取器。我使用 gcc -O3 标志进行编译以进行优化和 -lpapi 库。使用此代码,对于第三个循环,我得到:

L1_HIT:64,L1_MISS:1011,L2_HIT:15,L2_MISS:996。

但是,如果我在数组初始化之前取消注释 PAPI_library_init 并在之后注释它,我得到的结果是:

L1_HIT:73,L1_MISS:1004,L2_HIT:990,L2_MISS:14。

我正在 Skylake 服务器中对此进行测试,缓存大小为:

L1d cache:             32K
L1i cache:             32K
L2 cache:              1024K
L3 cache:              22528K

现在我有点困惑为什么 papi 初始化会影响这个结果。这是 L2 的命中和错过的变化。我只需要第三个循环,我相信前两个循环对计数器的影响没有被考虑在内。

因此,任何提示都会有所帮助,因为所有文档都说:“PAPI_library_init() 初始化 PAPI 库。必须在使用任何低级 PAPI 函数之前调用它。如果您的应用程序正在使用线程 PAPI_thread_init (3 ) 也必须在调用除 PAPI_library_init() 之外的库之前调用。"

4

0 回答 0