5

我有一个具有以下结构的代码

#pragma omp parallel
{
    #omp for nowait
    {
        // first for loop
    }

    #omp for nowait 
    {
        // first for loop
    }

    #pragma barrier 

    <-- #pragma omp single/critical/atomic --> not sure 
    dgemm_(....)

    #pragma omp for
    {
        // yet another for loop  
    }

}

对于 dgemm_,我与多线程 mkl 链接。我希望 mkl 使用所有可用的 8 个线程。最好的方法是什么?

4

2 回答 2

6

这是嵌套并行的情况。它受 MKL 支持,但仅当您的可执行文件是使用英特尔 C/C++ 编译器构建时才有效。这种限制的原因是 MKL 使用英特尔的 OpenMP 运行时,并且不同的 OMP 运行时不能很好地相互配合。

一旦解决了这个问题,您应该通过设置为来启用嵌套并行性,并通过设置为OMP_NESTEDTRUE禁用 MKL 对嵌套并行性的检测。如果要处理的数据是共享的,那么您必须从构造中调用后者。如果每个线程都处理自己的私有数据,那么您不需要任何同步结构,但使用多线程 MKL 也不会给您带来任何好处。因此,我假设您的情况是前者。MKL_DYNAMICFALSEdgemm_single

总结一下:

#pragma omp single
dgemm_(...);

并运行:

$ MKL_DYNAMIC=FALSE MKL_NUM_THREADS=8 OMP_NUM_THREADS=8 OMP_NESTED=TRUE ./exe

您还可以使用适当的调用设置参数:

mkl_set_dynamic(0);
mkl_set_num_threads(8);
omp_set_nested(1);

#pragma omp parallel num_threads(8) ...
{
   ...
}

虽然我更喜欢使用环境变量。

于 2013-12-21T18:39:28.030 回答
3

虽然这篇文章有点过时,但我仍然想为此提供一些有用的见解。

从功能的角度来看,上述答案是正确的,但从性能的角度来看不会给出最佳结果。原因是大多数 OpenMP 实现在线程到达障碍或没有工作要做时不会关闭线程。相反,线程将进入自旋等待循环并在等待时继续消耗处理器周期。

在示例中:

#pragma omp parallel
{
    #omp for nowait
    for(...) {}  // first loop

    #omp for
    for(...) {}  // second loop

    #pragma omp single
    dgemm_(....)

    #pragma omp for
    for(...) {}  // third loop
}

将会发生的情况是,即使dgemm调用在 MKL 中创建了额外的线程,外层线程仍将积极等待single构造结束,因此dgemm会以降低的性能运行。

这个问题基本上有两种解决方案:

1)列表项使用上面的代码,除了建议的环境变量外,还禁用主动等待:

$ MKL_DYNAMIC=FALSE MKL_NUM_THREADS=8 OMP_NUM_THREADS=8 OMP_NESTED=TRUE OMP_WAIT_MODE=passive ./exe

2)修改代码分割并行区域:

#pragma omp parallel
{
    #omp for nowait
    for(...) {}  // first loop

    #omp for nowait
    for(...) {}  // second loop
}

dgemm_(...);

#pragma omp parallel
    #pragma omp for nowait
    for(...) {}  // third loop
}

对于解决方案 1,线程立即进入睡眠模式并且不消耗周期。缺点是线程必须从这种更深的睡眠状态中唤醒,与自旋等待相比,这会增加延迟。

对于解决方案 2,线程保持在其自旋等待循环中,并且很可能在dgemm调用进入其并行区域时主动等待。额外的连接和分叉也会引入一些开销,但它可能比使用single构造或解决方案 1 的初始解决方案的超额订阅要好。

最好的解决方案取决于dgemm操作中完成的工作量与 fork/join 的同步开销相比,后者主要由线程数和内部实现主导。

于 2018-09-27T10:35:57.370 回答