【发布时间】:2013-11-13 02:09:07
【问题描述】:
我有一个例程,它对小矩阵(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 的新手,所以我确定我犯了新手错误。
谢谢, 安德鲁
【问题讨论】:
-
MKL 在 Phi 上的小矩阵存在一些严重的性能问题。我建议您在英特尔论坛上发布您的问题:software.intel.com/en-us/forums/intel-many-integrated-core
-
@pburka 我也发过帖子了。只是想撒一张更广的网。 :) 你有小矩阵问题的链接吗?
-
这是一个问题software.intel.com/en-us/forums/topic/475924。我还通过 Premier Support 跟进英特尔。在这种情况下,我相信 MKL 将线程数减少到 30 个,然后在 GEMM 调用后需要 1ms 来重新启动线程。但我也相信这不是唯一的 GEMM 性能问题。
-
@pburka 我刚刚在英特尔看到你的帖子,你的尺寸和我的差不多。我没有填充以被 64 维整除(我会尝试),但这似乎不是正确的答案。您是说(假设地)它会自动产生约 8 个线程来计算模型,每个线程为 dgemm 产生 30 个线程?还是我给了 OpenMP 太多的信任?您是否知道一种方法来确定谁在 Phi 上产生了哪些线程?
-
不知道什么好办法。我使用 gdb 逐步浏览了 MKL 以弄清楚它在做什么。 OpenMP 源是公开的,因此您可以对其进行检测。 openmprtl.org
标签: c openmp intel-mkl intel-vtune intel-mic