在 MPICH 中执行混合 OpenMP/MPI 作业
Executing hybrid OpenMP/MPI jobs in MPICH
我正在努力寻找使用 MPICH (hydra) 执行混合 OpenMP/MPI 作业的正确方法。
我可以很容易地启动进程并且它们确实创建了线程,但是无论我尝试过哪种类型的 -bind-to
,它们都被绑定到与其主线程相同的核心。
如果我将 GOMP_CPU_AFFINITY
显式设置为 0-15
,我会分散所有线程,但只有在每个节点有 1 个进程时才会提供。我不想要那个,我想要每个套接字一个进程。
设置OMP_PROC_BIND=false
没有明显效果。
我尝试过的许多不同组合的示例
export OMP_NUM_THREADS=8
export OMP_PROC_BIND="false"
mpiexec.hydra -n 2 -ppn 2 -envall -bind-to numa ./a.out
我得到的是所有进程都位于一个核心 0-7
上,100% 和多个线程位于核心 8-15
但其中只有一个接近 100%(它们正在等待第一个过程)。
由于 libgomp
缺少相当于英特尔 KMP_AFFINITY
的 respect
子句的等价物,您可以通过提供一个包装脚本来破解它,该脚本从 /proc/PID/status
(Linux-具体):
#!/bin/sh
GOMP_CPU_AFFINITY=$(grep ^Cpus_allowed_list /proc/self/status | grep -Eo '[0-9,-]+')
export GOMP_CPU_AFFINITY
exec $*
这应该与 -bind-to numa
一起使用。
当 运行 混合 MPI / OpenMP 代码时,只要 MPI 库和 OpenMP 运行time 没有,我确实有一个稍微不同的解决方案来将 OpenMP 线程绑定到套接字/NUMA 节点默认协作良好。这个想法是使用 numactl
及其绑定属性。这甚至具有额外的优势,不仅可以将线程绑定到套接字,还可以绑定内存,从而强制实现良好的内存局部性并最大化带宽。
为此,我首先禁用任何 MPI and/or OpenMP 绑定(前者使用相应的 mpiexec
选项,前者将 OMP_PROC_BIND
设置为 false
后者)。然后我使用以下 omp_bind.sh
shell 脚本:
#!/bin/bash
numactl --cpunodebind=$(( $PMI_ID % 2 )) --membind=$(( $PMI_ID % 2 )) "$@"
我 运行 我的代码是这样的:
OMP_PROC_BIND="false" OMP_NUM_THREADS=8 mpiexec -ppn 2 -bind-to-none omp_bind.sh a.out args
根据机器上的插座数量,2
需要在 shell 上进行调整。同样,PMI_ID
取决于所使用的 mpiexec
的版本。我有时看到MPI_RANK
、PMI_RANK
等
但无论如何,我总能找到一种让它工作的方法,内存绑定有时会非常方便,尤其是为了避免 IO 缓冲区耗尽第一个 NUMA 节点上的所有内存的潜在陷阱,从而导致第一个套接字上 运行ning 进程的代码内存,在第二个 NUMA 节点上分配内存。
我正在努力寻找使用 MPICH (hydra) 执行混合 OpenMP/MPI 作业的正确方法。
我可以很容易地启动进程并且它们确实创建了线程,但是无论我尝试过哪种类型的 -bind-to
,它们都被绑定到与其主线程相同的核心。
如果我将 GOMP_CPU_AFFINITY
显式设置为 0-15
,我会分散所有线程,但只有在每个节点有 1 个进程时才会提供。我不想要那个,我想要每个套接字一个进程。
设置OMP_PROC_BIND=false
没有明显效果。
我尝试过的许多不同组合的示例
export OMP_NUM_THREADS=8
export OMP_PROC_BIND="false"
mpiexec.hydra -n 2 -ppn 2 -envall -bind-to numa ./a.out
我得到的是所有进程都位于一个核心 0-7
上,100% 和多个线程位于核心 8-15
但其中只有一个接近 100%(它们正在等待第一个过程)。
由于 libgomp
缺少相当于英特尔 KMP_AFFINITY
的 respect
子句的等价物,您可以通过提供一个包装脚本来破解它,该脚本从 /proc/PID/status
(Linux-具体):
#!/bin/sh
GOMP_CPU_AFFINITY=$(grep ^Cpus_allowed_list /proc/self/status | grep -Eo '[0-9,-]+')
export GOMP_CPU_AFFINITY
exec $*
这应该与 -bind-to numa
一起使用。
当 运行 混合 MPI / OpenMP 代码时,只要 MPI 库和 OpenMP 运行time 没有,我确实有一个稍微不同的解决方案来将 OpenMP 线程绑定到套接字/NUMA 节点默认协作良好。这个想法是使用 numactl
及其绑定属性。这甚至具有额外的优势,不仅可以将线程绑定到套接字,还可以绑定内存,从而强制实现良好的内存局部性并最大化带宽。
为此,我首先禁用任何 MPI and/or OpenMP 绑定(前者使用相应的 mpiexec
选项,前者将 OMP_PROC_BIND
设置为 false
后者)。然后我使用以下 omp_bind.sh
shell 脚本:
#!/bin/bash
numactl --cpunodebind=$(( $PMI_ID % 2 )) --membind=$(( $PMI_ID % 2 )) "$@"
我 运行 我的代码是这样的:
OMP_PROC_BIND="false" OMP_NUM_THREADS=8 mpiexec -ppn 2 -bind-to-none omp_bind.sh a.out args
根据机器上的插座数量,2
需要在 shell 上进行调整。同样,PMI_ID
取决于所使用的 mpiexec
的版本。我有时看到MPI_RANK
、PMI_RANK
等
但无论如何,我总能找到一种让它工作的方法,内存绑定有时会非常方便,尤其是为了避免 IO 缓冲区耗尽第一个 NUMA 节点上的所有内存的潜在陷阱,从而导致第一个套接字上 运行ning 进程的代码内存,在第二个 NUMA 节点上分配内存。