为什么 `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_procs1:

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 threadsNumber 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可能会引起对缓存行的争夺,甚至可能会降低性能)。