运行包含openmp代码的MPI程序时是否需要设置OMP_NUM_THREADS变量?当我看到一些教程时,我看到你必须设置OMP_NUM_THREADS(环境变量)。我测试我的家庭集群上使用OpenMPI 1.6.4(MPI 2.1)传递消息的程序。我的MPI程序包含openMP函数调用(omp_get_max_threads),在运行MPI程序之前我没有设置OMP_NUM_THREADS变量。该程序正常工作并返回实际的线程数。如果我尝试在另一个使用较新版本的MPI实现(MPI 3.0)的集群上启动此程序,程序会在omp_get_max_threads()调用时返回1。我的程序使用了 -fopenmp 选项正在编译。我使用mpicc来编译我的程序。
int main(int argc, char *argv[]){
int rank=-1;
int n=-1;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
n=omp_get_max_threads();
printf("Hello from %d, omp_get_max_threads returned me %d\n",rank,omp_get_max_threads());
MPI_Finalize();
return 0;}
有什么问题?如何解决?如果您不相信我这里是screenshot调试窗口(程序输出+值(右上角))
我尝试了一些MPI选项(-H)并在1 HOST上运行该程序。我使用OpenMPI 1.8.1。检查程序输出:
[hpc@server Debug]$ mpirun -np 1 -H localhost ./mpiTest
Hello from 0, omp_get_max_threads returned me 2
[hpc@server Debug]$ mpirun -np 2 -H localhost ./mpiTest
Hello from 0, omp_get_max_threads returned me 8
Hello from 1, omp_get_max_threads returned me 8
[hpc@server Debug]$ mpirun -np 2 -hostfile ./hostfile ./mpiTest
Hello from 0, omp_get_max_threads returned me 2
Hello from 1, omp_get_max_threads returned me 2
[hpc@server Debug]$ mpirun -H server,server -np 2 ./mpiTest
Hello from 0, omp_get_max_threads returned me 2
Hello from 1, omp_get_max_threads returned me 2
[hpc@server Debug]$ mpirun -H server -np 2 ./mpiTest
Hello from 0, omp_get_max_threads returned me 8
Hello from 1, omp_get_max_threads returned me 8
第二次它返回了正确数量的cpu线程。怎么会这样?
答案 0 :(得分:2)
默认情况下,大多数OpenMP实现将最大线程数设置为等于逻辑CPU数。与MPI结合使用时,此默认设置无法正常工作。例如,如果在同一节点上启动2个混合MPI + OpenMP进程,则每个进程都会尝试使用所有可用的CPU,这将导致超额订阅。这就是为什么在我们的集群上我们为所有MPI作业设置OMP_NUM_THREADS
为1,如果用户正在启动混合作业,他必须明确地将OMP_NUM_THREADS
设置为每个所需的线程数MPI流程。
使用Open MPI启动混合作业的正确方法取决于您的群集环境。您应该将OMP_NUM_THREADS
设置为某个合理的值,然后让资源管理器将值传播到所有MPI进程或明确地执行此操作。
如果编译Open MPI时与集群资源管理器(SGE,LSF,PBS,Torque等)紧密集成,则以下(作为作业脚本的一部分)就足够了:
export OMP_NUM_THREADS=4
mpiexec -n 4 ./program <program arguments>
这将启动4个MPI进程,每个进程有4个OpenMP线程。
否则必须使用-x
选项才能将OMP_NUM_THREADS
的值传递给MPI进程:
$ export OMP_NUM_THREADS=4
$ mpiexec -x OMP_NUM_THREADS -H host1,host2,host3,host4 -n 4 ./program
默认情况下,Open MPI 1.8.x引入了流程绑定。您可以通过将--report-bindings
选项添加到mpiexec
来验证它,并观察打印的绑定信息。默认情况下,MPI进程分别绑定到单个(和不同的)CPU核心。这就是为什么OpenMP运行时默认情况下在每个核心具有单个硬件线程的机器上使用单个线程的原因 - 在单个核心上启动多个线程对大多数程序都没有好处。
要将行为还原回Open MPI 1.6.x,请添加禁用绑定的--bind-to none
命令行选项:
$ mpiexec --report-bindings -np 2 ./test
[cluster:28358] MCW rank 1 bound to socket 0[core 1[hwt 0]]: [./B/./././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.]
[cluster:28358] MCW rank 0 bound to socket 0[core 0[hwt 0]]: [B/././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.]
Hello from 0, omp_get_max_threads returned me 1
Hello from 1, omp_get_max_threads returned me 1
$ mpiexec --bind-to none --report-bindings -np 2 ./test
[cluster:28743] MCW rank 1 is not bound (or bound to all available processors)
[cluster:28743] MCW rank 0 is not bound (or bound to all available processors)
Hello from 0, omp_get_max_threads returned me 64
Hello from 1, omp_get_max_threads returned me 64
当您指定-H
选项时,其中列出的每个主机都会提供单个广告位。当您要求Open MPI启动比指定的插槽更多的进程(即您超额订阅主机)时,库会关闭默认绑定。这就是组合-H localhost -np 1
导致使用两个线程的原因,因为您提供了一个插槽并要求一个进程,因此该进程绑定到一个核心(在您的情况下,核心似乎有两个硬件线程)。组合-H localhost -np 2
在单个插槽上请求两个进程,即超额订阅,因此库禁用绑定机制,并且两个MPI进程可以访问所有8个硬件线程。组合-H server,server -np 2
为两个进程提供了两个槽,即没有超额订阅,因此绑定处于活动状态。
$ mpiexec -H localhost --report-bindings -np 1 ./test
[cluster:21425] MCW rank 0 bound to socket 0[core 0[hwt 0]]: [B/././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.]
Hello from 0, omp_get_max_threads returned me 1
$ mpiexec -H localhost --report-bindings -np 2 ./test
[cluster:38895] MCW rank 1 is not bound (or bound to all available processors)
[cluster:38895] MCW rank 0 is not bound (or bound to all available processors)
Hello from 1, omp_get_max_threads returned me 64
Hello from 0, omp_get_max_threads returned me 64
$ mpiexec -H localhost,localhost --report-bindings -np 2 ./test
[cluster:39329] MCW rank 1 bound to socket 0[core 1[hwt 0]]: [./B/./././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.]
[cluster:39329] MCW rank 0 bound to socket 0[core 0[hwt 0]]: [B/././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.][./././././././.]
Hello from 1, omp_get_max_threads returned me 1
Hello from 0, omp_get_max_threads returned me 1