【问题标题】:binding threads to certain MPI processes将线程绑定到某些 MPI 进程
【发布时间】:2016-02-08 05:41:26
【问题描述】:

我有以下设置,混合 MPI/OpenMP 代码 运行 M 个 MPI 进程,每个进程有 N 个线程。总共有 MxN 线程可用。

如果可能的话,我想做的是分配线程 仅适用于某些 MPI 进程,而不适用于所有进程,我的代码将 更有效率,因为一些线程只是在做 重复的工作。

谢谢。

【问题讨论】:

  • 我不确定我是否理解这个问题。您是否想保持MxN 全局线程数不变,但有一些 MPI 进程使用超过 N 线程,而其他一些会使用更少?还是您想实现其他目标?

标签: multithreading fortran mpi openmp


【解决方案1】:

您的问题是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>

它启动n1 运行executable_1 命令行参数&lt;args1&gt; 的队列,n2 运行executable_2 命令行参数&lt;args2&gt; 的队列,等等。总共启动了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 个不同的上下文。 &lt;local parameters&gt; 可以包括设置特定环境变量的值,例如在您的情况下,可能是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

无论选择哪种解决方案,进程和线程绑定都会变得有点棘手,可能应该完全关闭。

【讨论】:

  • 如果这不是你要找的答案,我的那个生锈的水晶球最后一次让我失望了……
  • 感谢您的解释。在我的代码中,我使用“mpirun -n”设置 MPI 等级数,然后使用“export OMP_NUM_THREADS”设置线程数。但是,此方法“不灵活”,因为为每个 MPI 等级分配了相同数量的线程,并且我正在浪费 CPU 功率,因为​​许多线程处于空闲或重复任务。这就是为什么我想要一些方案来分配例如 2 个线程用于 MPI=1、2、3 和 4 个线程用于 MPI=4、5、6。在某些时候,我需要设置障碍来同步来自不同 MPI 的数据。您提到的方法可以克服 MPI 问题上的不同线程?
  • @armando,使用上述方法,您可以为每个 MPI 等级设置不同数量的 OpenMP 线程。如何将 MPI 与这些线程结合使用是一个单独的问题。 MPI 很大程度上不知道线程的存在,并且所有通信都发生在进程级别,因此每个进程具有不同数量的线程应该不会出现问题。当然,如果 OpenMP 线程自己不调用 MPI。
  • 如果我启动我的程序的多个实例(每个实例具有不同数量的排名),是否会有一个用于所有排名的全局通信器和一个用于每个实例内排名的本地通信器?
【解决方案2】:

您可以使用绑定到核心来运行您的工作。然后,在执行期间,您可以使用 ISO_C_BINDINGS 在您的程序 (http://man7.org/linux/man-pages/man2/sched_setaffinity.2.html) 中调用 sched_setaffinity,因为它是一个 C 函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-02
    • 2021-12-26
    • 2011-07-05
    • 1970-01-01
    • 2010-11-30
    • 2015-01-16
    • 2011-04-05
    相关资源
    最近更新 更多