如何衡量并行程序的整体性能(使用papi)

Seb*_*ian 9 c performance multithreading blas papi

我问自己,衡量并行程序性能(触发器)的最佳方法是什么.我读到了papi_flops.这似乎适用于串行程序.但我不知道如何衡量并行程序的整体性能.

我想测量blas/lapack函数的性能,在我的gemm下面的例子中.但我也想测量其他功能,特别是功能不知道操作次数的地方.(在gemm的情况下,ops是已知的(ops(gemm)= 2*n ^ 3),因此我可以根据操作次数和执行时间计算性能.)库(我正在使用Intel MKL)自动生成线程.所以我不能单独测量每个线程的性能然后减少它.

这是我的例子:

#include <stdlib.h>                                                              
#include <stdio.h>                                                               
#include <string.h>                                                             
#include "mkl.h"
#include "omp.h"
#include "papi.h"       

int main(int argc, char *argv[] )                                                
{                                                                                
  int i, j, l, k, n, m, idx, iter;
  int mat, mat_min, mat_max;
  int threads;
  double *A, *B, *C;
  double alpha =1.0, beta=0.0;

  float rtime1, rtime2, ptime1, ptime2, mflops;
  long long flpops;

  #pragma omp parallel
  {
    #pragma omp master
    threads = omp_get_num_threads();
  }

  if(argc < 4){                                                                  
    printf("pass me 3 arguments!\n");                                            
    return( -1 );                                                                
  }                                                                              
  else                                                                           
  {                                                                            
    mat_min = atoi(argv[1]);
    mat_max = atoi(argv[2]);
    iter = atoi(argv[3]);                                                         
  }                    

  m = mat_max;  n = mat_max;  k = mat_max;

  printf (" Initializing data for matrix multiplication C=A*B for matrix \n"
            " A(%ix%i) and matrix B(%ix%i)\n\n", m, k, k, n);

  A = (double *) malloc( m*k * sizeof(double) );
  B = (double *) malloc( k*n * sizeof(double) );
  C = (double *) malloc( m*n * sizeof(double) );

  printf (" Intializing matrix data \n\n");
  for (i = 0; i < (m*k); i++)
    A[i] = (double)(i+1);
  for (i = 0; i < (k*n); i++)
    B[i] = (double)(-i-1);
  memset(C,0,m*n*sizeof(double));

  // actual meassurment
  for(mat=mat_min;mat<=mat_max;mat+=5)
  {
    m = mat;  n = mat; k = mat;

    for( idx=-1; idx<iter; idx++ ){
      PAPI_flops( &rtime1, &ptime1, &flpops, &mflops );
      cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 
                    m, n, k, alpha, A, k, B, n, beta, C, n);
      PAPI_flops( &rtime2, &ptime2, &flpops, &mflops );
    }

    printf("%d threads: %d in %f sec, %f MFLOPS\n",threads,mat,rtime2-rtime1,mflops);fflush(stdout);
  }

  printf("Done\n");fflush(stdout);

  free(A);
  free(B);
  free(C);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是一个输出(对于矩阵大小200):

1 threads: 200 in 0.001459 sec, 5570.258789 MFLOPS
2 threads: 200 in 0.000785 sec, 5254.993652 MFLOPS
4 threads: 200 in 0.000423 sec, 4919.640137 MFLOPS
8 threads: 200 in 0.000264 sec, 3894.036865 MFLOPS
Run Code Online (Sandbox Code Playgroud)

我们可以看到执行时间,函数gemm可以扩展.但我测量的翻牌只是线程0的表现.

我的问题是:我如何衡量整体表现?我很感激任何意见.

Bit*_*ler 4

首先,我只是好奇 - 为什么需要 FLOPS?你不关心花费了多少时间吗?或者与其他 BLAS 库相比可能花费的时间?

PAPI 是基于线程的,它本身没有太多帮助。

我要做的是围绕函数调用进行测量,并查看时间如何随着它生成的线程数量而变化。它不应该产生比物理核心更多的线程(HT 在这里不好)。然后,如果矩阵足够大,并且机器没有加载,则时间应该简单地除以线程数。例如,4 核上的 10 秒应变为 2.5 秒。

除此之外,您可以做两件事来真正测量它:
1. 使用您现在使用的任何东西,但在 BLAS 代码周围注入开始/结束测量代码。实现此目的的一种方法(在 Linux 中)是预加载一个定义 pthread_start 的库,并使用您自己的函数来调用原始函数,但进行一些额外的测量。当进程已经运行时覆盖函数指针的另一种方法(=trampoline)。在 Linux 中,它位于 GOT/PLT 中,而在 Windows 中,它更复杂 - 查找库。
2. 使用 oprofile 或其他分析器报告在您关心的时间内执行的指令数。或者更好的是,报告执行的浮点指令的数量。这样做的一个小问题是,SSE 指令一次会乘法或加法 2 个或更多双精度数,因此您必须考虑到这一点。我想你可以假设他们总是使用尽可能多的操作数。