将线程绑定到某些 MPI 进程
binding threads to certain MPI processes
我有以下设置,一个混合 MPI/OpenMP 代码
运行 M 个 MPI 进程,每个进程有 N 个线程。总共有
MxN 线程可用。
如果可能的话,我想做的是分配线程
只针对某些 MPI 进程而不是所有进程,我的代码会
更有效率,因为一些线程只是在做
重复性工作。
谢谢。
您可以使用绑定到内核来 mpirun 作业。然后,在执行期间,您可以使用 ISO_C_BINDINGS 在您的程序 (http://man7.org/linux/man-pages/man2/sched_setaffinity.2.html) 中调用 sched_setaffinity,因为它是一个 C 函数。
您的问题是 this one 的一般化版本。至少有三种可能的解决方案。
对于大多数 MPI 实现,可以启动多个具有自己环境(上下文)的可执行文件作为同一 MPI 作业的一部分。它被称为 MPMD(多程序多数据)或 MIMD(多指令多数据)模型。语法通常包括 :
(冒号)作为分隔符:
$ mpiexec <global parameters>
-n n1 <local parameters> executable_1 <args1> :
-n n2 <local parameters> executable_2 <args2> :
...
-n nk <local parameters> executable_k <argsk>
它使用命令行参数 <args1>
、n2
ranks 运行ning [=23] 启动 n1
ranks 运行ning executable_1
=] 与命令行参数 <args2>
,等等。总共启动了 n1 + n2 + ... + nk
个进程并且线性分配了等级:
Ranks (from .. to) | Executable
====================|=============
0 .. n1-1 | executable_1
n1 .. n1+n2-1 | executable_2
n1+n2 .. n1+n2+n3-1 | executable_3
... | ...
作为更窄的情况,可以指定相同的可执行文件 k 次,以便使用相同的可执行文件获得 k 不同的上下文. <local parameters>
可以包括设置特定环境变量的值,例如在你的情况下可能是 OMP_NUM_THREADS
。指定环境的确切方法因一种实现而异。使用 Open MPI,可以这样做:
mpiexec --hostfile all_hosts \
-n 5 -x OMP_NUM_THREADS=2 myprog : \
-n 4 -x OMP_NUM_THREADS=4 myprog : \
-n 6 -x OMP_NUM_THREADS=1 myprog
这将在 all_hosts
(全局参数)中指定的主机上启动 15 个 MPI 等级,前五个使用两个 OpenMP 线程,接下来的四个 - 四个 OpenMP 线程,最后六个 运行宁顺序。对于基于 MPICH 的实现,命令会略有不同:
mpiexec --hostfile all_hosts \
-n 5 -env OMP_NUM_THREADS 2 myprog : \
-n 4 -env OMP_NUM_THREADS 4 myprog : \
-n 6 -env OMP_NUM_THREADS 1 myprog
虽然得到广泛支持,但以前的方法有点不灵活。如果有人想要除了每 10 个 运行 顺序之外的所有等级?那么命令行就变成了:
mpiexec ...
-n 9 -x OMP_NUM_THREADS=1 myprog : \
-n 1 -x OMP_NUM_THREADS=N myprog : \
-n 9 -x OMP_NUM_THREADS=1 myprog : \
-n 1 -x OMP_NUM_THREADS=N myprog : \
...
一个更方便的解决方案是提供一个根据进程等级设置 OMP_NUM_THREADS
的包装器。例如,Open MPI 的包装器如下所示:
#!/bin/bash
if [ $((($OMPI_COMM_WORLD_RANK + 1) % 10)) == 0 ]; then
export OMP_NUM_THREADS=N
else
export OMP_NUM_THREADS=1
fi
exec "$*"
并简单地用作:
mpiexec -n M ... mywrapper.sh myprog <args>
第三个也是最不灵活的选项是在 MPI 初始化之后但在任何并行区域之前从程序内部简单地调用 omp_set_num_threads()
,并根据等级设置不同的线程数:
integer :: provided, rank, ierr
call MPI_INIT_THREAD(MPI_THREAD_FUNNELED, provided, ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
if (mod(rank, 10) == 0) then
call omp_set_num_threads(N)
else
call omp_set_num_threads(1)
end if
无论选择什么解决方案,进程和线程绑定都会变得有点棘手,应该完全关闭。
我有以下设置,一个混合 MPI/OpenMP 代码 运行 M 个 MPI 进程,每个进程有 N 个线程。总共有 MxN 线程可用。
如果可能的话,我想做的是分配线程 只针对某些 MPI 进程而不是所有进程,我的代码会 更有效率,因为一些线程只是在做 重复性工作。
谢谢。
您可以使用绑定到内核来 mpirun 作业。然后,在执行期间,您可以使用 ISO_C_BINDINGS 在您的程序 (http://man7.org/linux/man-pages/man2/sched_setaffinity.2.html) 中调用 sched_setaffinity,因为它是一个 C 函数。
您的问题是 this one 的一般化版本。至少有三种可能的解决方案。
对于大多数 MPI 实现,可以启动多个具有自己环境(上下文)的可执行文件作为同一 MPI 作业的一部分。它被称为 MPMD(多程序多数据)或 MIMD(多指令多数据)模型。语法通常包括 :
(冒号)作为分隔符:
$ mpiexec <global parameters>
-n n1 <local parameters> executable_1 <args1> :
-n n2 <local parameters> executable_2 <args2> :
...
-n nk <local parameters> executable_k <argsk>
它使用命令行参数 <args1>
、n2
ranks 运行ning [=23] 启动 n1
ranks 运行ning executable_1
=] 与命令行参数 <args2>
,等等。总共启动了 n1 + n2 + ... + nk
个进程并且线性分配了等级:
Ranks (from .. to) | Executable
====================|=============
0 .. n1-1 | executable_1
n1 .. n1+n2-1 | executable_2
n1+n2 .. n1+n2+n3-1 | executable_3
... | ...
作为更窄的情况,可以指定相同的可执行文件 k 次,以便使用相同的可执行文件获得 k 不同的上下文. <local parameters>
可以包括设置特定环境变量的值,例如在你的情况下可能是 OMP_NUM_THREADS
。指定环境的确切方法因一种实现而异。使用 Open MPI,可以这样做:
mpiexec --hostfile all_hosts \
-n 5 -x OMP_NUM_THREADS=2 myprog : \
-n 4 -x OMP_NUM_THREADS=4 myprog : \
-n 6 -x OMP_NUM_THREADS=1 myprog
这将在 all_hosts
(全局参数)中指定的主机上启动 15 个 MPI 等级,前五个使用两个 OpenMP 线程,接下来的四个 - 四个 OpenMP 线程,最后六个 运行宁顺序。对于基于 MPICH 的实现,命令会略有不同:
mpiexec --hostfile all_hosts \
-n 5 -env OMP_NUM_THREADS 2 myprog : \
-n 4 -env OMP_NUM_THREADS 4 myprog : \
-n 6 -env OMP_NUM_THREADS 1 myprog
虽然得到广泛支持,但以前的方法有点不灵活。如果有人想要除了每 10 个 运行 顺序之外的所有等级?那么命令行就变成了:
mpiexec ...
-n 9 -x OMP_NUM_THREADS=1 myprog : \
-n 1 -x OMP_NUM_THREADS=N myprog : \
-n 9 -x OMP_NUM_THREADS=1 myprog : \
-n 1 -x OMP_NUM_THREADS=N myprog : \
...
一个更方便的解决方案是提供一个根据进程等级设置 OMP_NUM_THREADS
的包装器。例如,Open MPI 的包装器如下所示:
#!/bin/bash
if [ $((($OMPI_COMM_WORLD_RANK + 1) % 10)) == 0 ]; then
export OMP_NUM_THREADS=N
else
export OMP_NUM_THREADS=1
fi
exec "$*"
并简单地用作:
mpiexec -n M ... mywrapper.sh myprog <args>
第三个也是最不灵活的选项是在 MPI 初始化之后但在任何并行区域之前从程序内部简单地调用 omp_set_num_threads()
,并根据等级设置不同的线程数:
integer :: provided, rank, ierr
call MPI_INIT_THREAD(MPI_THREAD_FUNNELED, provided, ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
if (mod(rank, 10) == 0) then
call omp_set_num_threads(N)
else
call omp_set_num_threads(1)
end if
无论选择什么解决方案,进程和线程绑定都会变得有点棘手,应该完全关闭。