确保混合MPI / OpenMP在每个OpenMP线程上运行不同的核心

7
我正在尝试运行混合OpenMP/MPI作业,以便将OpenMP线程按核心分离(每个核心只有一个线程)。我看到其他答案使用numa-ctl和bash脚本来设置环境变量,但我不想这样做。
我希望能够仅通过在命令行上设置OMP_NUM_THREADS和/或OMP_PROC_BIND以及mpiexec选项来实现此目的。我已经尝试了以下内容 - 假设我想要2个MPI进程,每个进程有2个OpenMP线程,并且每个线程都在单独的核心上运行,因此我需要4个核心。
OMP_PROC_BIND=true OMP_PLACES=cores OMP_NUM_THREADS=2 mpiexec -n 2 

这样分割任务,只有两个进程在工作,并且它们都在同一个CPU上运行,因此它们每个进程只使用大约25%的CPU。如果我尝试:

OMP_PROC_BIND=false OMP_PLACES=cores OMP_NUM_THREADS=2 mpiexec -n 2

那么,我只是得到了两个独立的MPI进程,每个进程都在使用100%或超过100%的CPU处理能力,根据top命令。这似乎没有显示不同的核心用于OpenMP线程。

我该如何强制系统将单独的线程放置在单独的核心上?

顺便说一下,lscpu命令输出如下:

-CPU(s):                48
-On-line CPU(s) list:   0-47
-Thread(s) per core:    2
-Core(s) per socket:    12
-Socket(s):             2
-NUMA node(s):          2

3
这是一个两步的操作。首先,将一个 MPI 任务绑定到两个内核上,然后每个内核绑定一个 OpenMP 线程。前者没有标准,你正在使用哪个 MPI 库和版本? - Gilles Gouaillardet
1
我正在使用mpi/mpich-3.2-x86_64。 - v2v1
@GillesGouaillardet,有什么想法吗? - v2v1
我不熟悉 mpichman mpiexec 中是否提到了绑定的内容? - Gilles Gouaillardet
2个回答

6
实际上,我期望你的第一个例子可以工作。在此设置OMP_PROC_BIND=true很重要,这样当OpenMP固定其线程时,它会保持在MPI进程的CPU绑定内。
根据批处理系统和MPI实现的不同,可能有非常个性化的设置方式。
此外,超线程或者说每个核心的多个硬件线程,在Linux中都显示为“核心”,这可能是问题的一部分,因为当两个进程运行在一个核心的两个超线程上时,你永远看不到200%。
这里是一个通用解决方案,我用来解决一些系统上某些MPI和一些OpenMP实现的问题。Cray的文档包含一个非常有用的程序,叫做xthi.c,可以快速找出问题所在,从这里搜索该文件名,或者从这里复制(不确定在这里复制是否合法...)。使用以下命令进行编译:
mpicc xthi.c -fopenmp -o xthi

现在,我们可以清晰地了解到发生了什么。例如,在一台2x 8核Xeon处理器上启用Hyperthreading和Intel MPI(基于MPICH),我们得到以下结果:

$ OMP_PROC_BIND=true OMP_PLACES=cores OMP_NUM_THREADS=2 mpiexec -n 2 ./xthi

Hello from rank 0, thread 0, on localhost. (core affinity = 0,16)
Hello from rank 0, thread 1, on localhost. (core affinity = 1,17)
Hello from rank 1, thread 0, on localhost. (core affinity = 8,24)
Hello from rank 1, thread 1, on localhost. (core affinity = 9,25)

正如您所看到的,核心意味着一个核心的所有超线程。请注意,默认情况下,mpirun 也会将其钉在不同的插座上。而使用 OMP_PLACES=threads 可以使每个核心占用一个线程:

$ OMP_PROC_BIND=true OMP_PLACES=threads OMP_NUM_THREADS=2 mpiexec -n 2 ./xthi
Hello from rank 0, thread 0, on localhost. (core affinity = 0)
Hello from rank 0, thread 1, on localhost. (core affinity = 1)
Hello from rank 1, thread 0, on localhost. (core affinity = 8)
Hello from rank 1, thread 1, on localhost. (core affinity = 9)

使用OMP_PROC_BIND=false(第二个示例),我得到:

$ OMP_PROC_BIND=false OMP_PLACES=cores OMP_NUM_THREADS=2 mpiexec -n 2 ./xthi
Hello from rank 0, thread 0, on localhost. (core affinity = 0-7,16-23)
Hello from rank 0, thread 1, on localhost. (core affinity = 0-7,16-23)
Hello from rank 1, thread 0, on localhost. (core affinity = 8-15,24-31)
Hello from rank 1, thread 1, on localhost. (core affinity = 8-15,24-31)

在这里,每个OpenMP线程都获得一个完整的套接字,因此MPI排名仍然在不同的资源上运行。但是,在一个进程内,OpenMP线程可能会被操作系统随意地调度到所有核心上。这与在我的测试系统上设置OMP_NUM_THREADS=2是一样的。
再次说明,这可能取决于特定的OpenMP和MPI实现和版本,但我认为您可以通过上面的描述轻松理解情况。
希望对您有所帮助。

3
你可以尝试这个。
OMP_PROC_BIND=true OMP_PLACES=cores OMP_NUM_THREADS=2 mpiexec -bind-to core:2 -n 2 ./xthi

一个MPI任务绑定在两个核心上,希望OpenMP运行时会将每个线程绑定到一个被分配给MPI任务的单个核心上。
为了检查MPI绑定是否正常工作,您可以简单地:
$ mpiexec -np 2 -bind-to core:2 grep Cpus_allowed_list /proc/self/status
Cpus_allowed_list:  0-1
Cpus_allowed_list:  2-3

谢谢!使用 grep Cpus_allowed_list /proc/self/status 命令真的很有帮助。我发现在我的笔记本电脑上,这个命令只给了我两个 CPU 核心,这太奇怪了。mpirun --pernode grep Cpus_allowed_list /proc/self/status - Y00

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接