我有一个例程,在小矩阵(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报告了很好的并行化(在使用8个CPU时花费了近100%的时间) . 现在,当我编译代码以在本机模式下运行Phi卡(使用-mmic)时,在mic0上的命令提示符下运行时,版本1和2都需要大约30秒 . 当我使用VTune对其进行分析时:
-
版本1大约需要30秒,热点分析显示大部分时间花在__kmp_wait_sleep和__kmp_static_yield上 . 在7710秒的CPU时间内,5804秒花费在旋转时间上 .
-
版本2需要fooooorrrreevvvver ...我在VTune运行几分钟后杀了它 . 热点分析显示,在25254s的CPU时间内,[vmlinux]花费了21585s .
任何人都可以了解这里发生的事情以及为什么我会遇到如此糟糕的表现?我正在使用OMP_NUM_THREADS的默认值并设置KMP_AFFINITY = compact,granularity = fine(由Intel推荐) . 我是MKL和OpenMP的新手,所以我确定我犯了新手的错误 .
谢谢,安德鲁
2 回答
考虑到大部分时间花在OS(vmlinux)上,这种行为最可能的原因是由于嵌套的OpenMP并行区域在
cblas_dgemm()
和dgesv
的MKL实现中引起的超额预订 . 例如 . 见this example .Jim Dempsey在Intel forum支持和解释了这个版本 .
使用MKL怎么样:顺序库?如果将MKL库与顺序选项链接,则它不会在MKL本身内部生成OpenMP线程 . 我想你可能会比现在更好 .