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

Posted

技术标签:

【中文标题】确保混合 MPI / OpenMP 在不同的内核上运行每个 OpenMP 线程【英文标题】:Ensure hybrid MPI / OpenMP runs each OpenMP thread on a different core 【发布时间】:2018-05-29 00:34:08 【问题描述】:

我正在尝试运行混合 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 功率运行,根据顶部。这似乎没有显示用于 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

【问题讨论】:

这是一个两步探戈。首先,将一个 MPI 任务绑定到两个内核,然后每个内核绑定一个 OpenMP 线程。前者没有标准,你运行的是哪个 MPI 库和版本? 我正在使用 mpi/mpich-3.2-x86_64 知道@GillesGouaillardet 吗? 我不熟悉mpichman mpiexec 有没有提到绑定? 【参考方案1】:

实际上,我希望您的第一个示例能够正常工作。在此处设置 OMP_PROC_BIND=true 很重要,这样 OpenMP 在固定线程时会保持在来自 MPI 进程的 CPU 绑定内。

根据批处理系统和 MPI 实现,可能有非常独特的方式来设置这些东西。

此外,超线程,或者通常每个内核有多个硬件线程,在你的 Linux 中都显示为“内核”,这可能是问题的一部分,因为当两个进程在两个超线程上运行时,你永远不会看到 200%一个核心。

这是一个通用解决方案,我在为某些 MPI 和某些系统上的某些 OpenMP 实现计算这些东西时使用。 Cray 的文档包含一个 非常 有用的程序,可以快速解决这些问题,它被称为 xthi.c、google the filename 或从 here 粘贴(不确定在此处粘贴是否合法...)。编译:

mpicc xthi.c -fopenmp -o xthi

现在我们可以看到到底发生了什么,例如在具有超线程和英特尔 MPI(基于 MPICH)的 2x 8 核 Xeon 上,我们得到:

$ 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 实现和版本,但我想您会很容易通过上面的描述弄清楚发生了什么。

希望对您有所帮助。

【讨论】:

【参考方案2】:

你可以试试这个

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

以上是关于确保混合 MPI / OpenMP 在不同的内核上运行每个 OpenMP 线程的主要内容,如果未能解决你的问题,请参考以下文章

OpenMP 和 MPI 混合程序

在 MPICH 中执行混合 OpenMP/MPI 作业

LSF 中的混合 MPI/OpenMP

MPI +线程并行化与仅MPI的优势(如果有的话)是什么?

MPI和OpenMP混合编程并行计算--入门程序

共享内存的 MPI 与 openMP