确保混合 MPI/OpenMP 在不同的核心上运行每个 OpenMP 线程
Ensure hybrid MPI / OpenMP runs each OpenMP thread on a different core
我正在尝试将 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 进程,每个 运行ning 都达到其 CPU 功率的 100% 或超过 100%,根据 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
实际上,我希望您的第一个示例能够正常工作。在这里设置 OMP_PROC_BIND=true
很重要,这样 OpenMP 在固定它的线程时会保持在 MPI 进程的 CPU 绑定范围内。
根据批处理系统和 MPI 实现,可能有非常独特的方法来设置这些东西。
还有超线程,或者通常每个内核有多个硬件线程,在您的 Linux 中都显示为 "cores",这可能是问题的一部分,因为当您永远看不到 200% 时一个内核的两个超线程上的两个进程运行。
这是一个通用解决方案,我在为某些系统上的某些 MPI 和某些 OpenMP 实现计算这些东西时使用。
Cray 的文档包含一个 非常 有用的程序来快速解决这些问题,它称为 xthi.c
、google the filename or paste it from here(不确定将其粘贴到此处是否合法...)。编译:
mpicc xthi.c -fopenmp -o xthi
现在我们可以看到到底发生了什么,例如在具有超线程和 Intel 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 线程可能会被 OS 跨所有内核疯狂调度。这与在我的测试系统上设置 OMP_NUM_THREADS=2
相同。
同样,这可能取决于特定的 OpenMP 和 MPI 实现和版本,但我认为您会根据上述描述轻松弄清楚发生了什么。
希望对您有所帮助。
你可以试试这个
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
我正在尝试将 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 进程,每个 运行ning 都达到其 CPU 功率的 100% 或超过 100%,根据 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
实际上,我希望您的第一个示例能够正常工作。在这里设置 OMP_PROC_BIND=true
很重要,这样 OpenMP 在固定它的线程时会保持在 MPI 进程的 CPU 绑定范围内。
根据批处理系统和 MPI 实现,可能有非常独特的方法来设置这些东西。
还有超线程,或者通常每个内核有多个硬件线程,在您的 Linux 中都显示为 "cores",这可能是问题的一部分,因为当您永远看不到 200% 时一个内核的两个超线程上的两个进程运行。
这是一个通用解决方案,我在为某些系统上的某些 MPI 和某些 OpenMP 实现计算这些东西时使用。
Cray 的文档包含一个 非常 有用的程序来快速解决这些问题,它称为 xthi.c
、google the filename or paste it from here(不确定将其粘贴到此处是否合法...)。编译:
mpicc xthi.c -fopenmp -o xthi
现在我们可以看到到底发生了什么,例如在具有超线程和 Intel 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 线程可能会被 OS 跨所有内核疯狂调度。这与在我的测试系统上设置 OMP_NUM_THREADS=2
相同。
同样,这可能取决于特定的 OpenMP 和 MPI 实现和版本,但我认为您会根据上述描述轻松弄清楚发生了什么。
希望对您有所帮助。
你可以试试这个
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