6

我有一个例程对小矩阵(50-100 x 1000 元素)执行一些 MKL 调用以拟合模型,然后我调用不同的模型。在伪代码中:

double doModelFit(int model, ...) {
   ...
   while( !done ) {
     cblas_dgemm(...);
     cblas_dgemm(...);
     ...
     dgesv(...);
     ...
   }
   return result;
}

int main(int argc, char **argv) {
  ...
  c_start = 1;  c_stop = nmodel;
  for(int c=c_start; c<c_stop; c++) {
    ...
    result = doModelFit(c, ...);
    ...
  }
}

调用上面的版本1。由于模型是独立的,所以我可以使用OpenMP线程来并行化模型拟合,如下(版本2):

int main(int argc, char **argv) {
  ...
  int numthreads=omp_max_num_threads();
  int c;
#pragma omp parallel for private(c)
  for(int t=0; t<numthreads; t++) {  
     // assuming nmodel divisible by numthreads...      
     c_start = t*nmodel/numthreads+1; 
     c_end = (t+1)*nmodel/numthreads;
     for(c=c_start; c<c_stop; c++) {
        ...
        result = doModelFit(c, ...);
        ...
     }
  }
}

当我在主机上运行版本 1 时,大约需要 11 秒,并且 VTune 报告并行化较差,大部分时间都处于空闲状态。主机上的版本 2 大约需要 5 秒,并且 VTune 报告了出色的并行化(几乎 100% 的时间花费在使用 8 个 CPU 上)。现在,当我编译代码以在本机模式下(使用 -mmic)在 Phi 卡上运行时,在 mic0 上的命令提示符下运行时,版本 1 和 2 都需要大约 30 秒。当我使用 VTune 对其进行分析时:

  • 版本 1 大约需要 30 秒,热点分析表明大部分时间都花在了 __kmp_wait_sleep 和 __kmp_static_yield 上。在 7710 秒 CPU 时间中,有 5804 秒用于自旋时间。
  • 版本 2 需要 fooooorrrreevvvver... 在 VTune 中运行几分钟后,我将其杀死。热点分析表明,25254s的CPU时间中,有21585s花费在[vmlinux]上。

谁能解释这里发生了什么以及为什么我的表现如此糟糕?我使用 OMP_NUM_THREADS 的默认值并设置 KMP_AFFINITY=compact,granularity=fine(如英特尔推荐的那样)。我是 MKL 和 OpenMP 的新手,所以我确定我犯了新手错误。

谢谢,安德鲁

4

2 回答 2

1

鉴于大部分时间都花在 OS (vmlinux) 上,这种行为最可能的原因是 MKL 实现中嵌套的 OpenMP 并行区域cblas_dgemm()dgesv. 例如看这个例子

此版本由英特尔论坛上的 Jim Dempsey 提供支持和解释。

于 2014-07-31T11:45:33.237 回答
0

使用 MKL:sequential 库怎么样?如果将 MKL 库与顺序选项链接,它不会在 MKL 本身内部生成 OpenMP 线程。我想你可能会得到比现在更好的结果。

于 2015-07-29T20:18:33.610 回答