为什么 `total_num_virtual_procs` 不等于 MPI 进程数?
Why is `total_num_virtual_procs` not equal to the amount of MPI processes?
NEST模拟器中有虚拟进程的概念。阅读有关 virtual processes 的信息,我希望每个 MPI 进程至少包含 1 个虚拟进程,否则该 MPI 进程什么都不做?
但是,当我启动 4 个 MPI 进程时,内核状态属性 total_num_virtual_procs
是 1
:
mpiexec -n 4 python -c "import nest; import mpi4py.MPI; print(nest.GetKernelStatus()['total_num_virtual_procs'], mpi4py.MPI.COMM_WORLD.Get_size());"
这会打印 NEST 导入文本和 1 4
四次。这是否意味着在我执行 nest.SetKernelStatus({'total_num_virtual_procs': 4})
之前不会将 3 个进程用于模拟?
编辑:TL;DR:nest.GetKernelStatus('total_num_virtual_procs')
的 return 值在以前的 NEST 版本中存在错误。最近的版本显示正确的数字,默认情况下每个进程一个线程,所以 MPI 进程的数量。
虚拟进程数是NEST的一个自由参数,因为它使用MPI + OpenMP的混合并行化方案。每个进程可能有多个线程,每个线程都是它自己的虚拟进程,例如两个进程和四个 VPs 导致每个进程两个线程:
Process Thread VP
------- ------ --
0 0 0
1 0 1
0 1 2
1 1 3
将 total_num_virtual_procs
设置为八,每个进程将产生四个线程,依此类推。你上面的例子即使没有 mpi4py
也能像这样工作:
mpiexec -n 2 python -c "\
import nest; \
nest.SetKernelStatus({'total_num_virtual_procs': 4}); \
print('>>> this is process %d of %d with %d threads <<<' \
% ( nest.Rank(),
nest.NumProcesses(), \
nest.GetKernelStatus()['total_num_virtual_procs']/nest.NumProcesses()) \
); \
nest.Simulate(10);"
它的输出中有以下几行:
…
>>> this is process 1 of 2 with 2 threads <<<
>>> this is process 0 of 2 with 2 threads <<<
…
Sep 09 15:49:39 SimulationManager::start_updating_ [Info]:
Number of local nodes: 0
Simulation time (ms): 10
Number of OpenMP threads: 2
Number of MPI processes: 2
Sep 09 15:49:39 SimulationManager::start_updating_ [Info]:
Number of local nodes: 0
Simulation time (ms): 10
Number of OpenMP threads: 2
Number of MPI processes: 2
您可以看到 total_num_virtual_procs
被拆分到所有进程中,因此 Number of OpenMP threads
次 Number of MPI processes
等于 total_num_virtual_procs
。您还注意到,您在 Python 级别看不到线程并行化,因为进程仅在 Create()
、Connect()
和 Simulate()
调用中进入并行上下文下面的 C++ 范围。
如果您不设置 total_num_virtual_procs
,则默认设置为 每个进程一个线程 。您可以通过在例如两个进程上创建多个神经元 nest.Create('iaf_psc_exp', 10)
来看到这一点:
Sep 09 16:28:28 SimulationManager::start_updating_ [Info]:
Number of local nodes: 5
Number of local nodes: 5
Simulation time (ms): 10
Simulation time (ms): 10
Number of OpenMP threads: 1
Number of OpenMP threads: 1
Number of MPI processes: 2
Number of MPI processes: 2
每个进程处理创建的十个神经元中的五个。 (nest.GetKernelStatus('total_num_virtual_procs')
应该 return 进程数。您使用的是哪个 NEST 版本?这已经修复了……)
如果你要设置的VPs个数不是MPI进程的倍数NEST会抛出异常
nest.lib.hl_api_exceptions.BadProperty: ('BadProperty in SetKernelStatus: Number of virtual processes (threads*processes) must be an integer multiple of the number of processes. Value unchanged.', 'BadProperty', 'SetKernelStatus', ': Number of virtual processes (threads*processes) must be an integer multiple of the number of processes. Value unchanged.')`
在尝试不同的作业几何结构时,通常好的起点是每个 NUMA 域一个 MPI 进程(例如每个物理 cpu 插槽一个进程)和每个物理内核一个线程(hyper-threading可能会引起对缓存行的争夺,甚至可能会降低性能)。
NEST模拟器中有虚拟进程的概念。阅读有关 virtual processes 的信息,我希望每个 MPI 进程至少包含 1 个虚拟进程,否则该 MPI 进程什么都不做?
但是,当我启动 4 个 MPI 进程时,内核状态属性 total_num_virtual_procs
是 1
:
mpiexec -n 4 python -c "import nest; import mpi4py.MPI; print(nest.GetKernelStatus()['total_num_virtual_procs'], mpi4py.MPI.COMM_WORLD.Get_size());"
这会打印 NEST 导入文本和 1 4
四次。这是否意味着在我执行 nest.SetKernelStatus({'total_num_virtual_procs': 4})
之前不会将 3 个进程用于模拟?
编辑:TL;DR:nest.GetKernelStatus('total_num_virtual_procs')
的 return 值在以前的 NEST 版本中存在错误。最近的版本显示正确的数字,默认情况下每个进程一个线程,所以 MPI 进程的数量。
虚拟进程数是NEST的一个自由参数,因为它使用MPI + OpenMP的混合并行化方案。每个进程可能有多个线程,每个线程都是它自己的虚拟进程,例如两个进程和四个 VPs 导致每个进程两个线程:
Process Thread VP
------- ------ --
0 0 0
1 0 1
0 1 2
1 1 3
将 total_num_virtual_procs
设置为八,每个进程将产生四个线程,依此类推。你上面的例子即使没有 mpi4py
也能像这样工作:
mpiexec -n 2 python -c "\
import nest; \
nest.SetKernelStatus({'total_num_virtual_procs': 4}); \
print('>>> this is process %d of %d with %d threads <<<' \
% ( nest.Rank(),
nest.NumProcesses(), \
nest.GetKernelStatus()['total_num_virtual_procs']/nest.NumProcesses()) \
); \
nest.Simulate(10);"
它的输出中有以下几行:
…
>>> this is process 1 of 2 with 2 threads <<<
>>> this is process 0 of 2 with 2 threads <<<
…
Sep 09 15:49:39 SimulationManager::start_updating_ [Info]:
Number of local nodes: 0
Simulation time (ms): 10
Number of OpenMP threads: 2
Number of MPI processes: 2
Sep 09 15:49:39 SimulationManager::start_updating_ [Info]:
Number of local nodes: 0
Simulation time (ms): 10
Number of OpenMP threads: 2
Number of MPI processes: 2
您可以看到 total_num_virtual_procs
被拆分到所有进程中,因此 Number of OpenMP threads
次 Number of MPI processes
等于 total_num_virtual_procs
。您还注意到,您在 Python 级别看不到线程并行化,因为进程仅在 Create()
、Connect()
和 Simulate()
调用中进入并行上下文下面的 C++ 范围。
如果您不设置
total_num_virtual_procs
,则默认设置为 每个进程一个线程 。您可以通过在例如两个进程上创建多个神经元nest.Create('iaf_psc_exp', 10)
来看到这一点:Sep 09 16:28:28 SimulationManager::start_updating_ [Info]: Number of local nodes: 5 Number of local nodes: 5 Simulation time (ms): 10 Simulation time (ms): 10 Number of OpenMP threads: 1 Number of OpenMP threads: 1 Number of MPI processes: 2 Number of MPI processes: 2
每个进程处理创建的十个神经元中的五个。 (
nest.GetKernelStatus('total_num_virtual_procs')
应该 return 进程数。您使用的是哪个 NEST 版本?这已经修复了……)如果你要设置的VPs个数不是MPI进程的倍数NEST会抛出异常
nest.lib.hl_api_exceptions.BadProperty: ('BadProperty in SetKernelStatus: Number of virtual processes (threads*processes) must be an integer multiple of the number of processes. Value unchanged.', 'BadProperty', 'SetKernelStatus', ': Number of virtual processes (threads*processes) must be an integer multiple of the number of processes. Value unchanged.')`
在尝试不同的作业几何结构时,通常好的起点是每个 NUMA 域一个 MPI 进程(例如每个物理 cpu 插槽一个进程)和每个物理内核一个线程(hyper-threading可能会引起对缓存行的争夺,甚至可能会降低性能)。