10.4. 跨主机调度进程
Open MPI提供了多种选项用于在主机间调度应用程序进程,包括将进程超额分配给处理器。本节将描述如何定义这种映射关系。
10.4.1. 调度概述
如果您没有超额订阅主机资源(即尝试运行的进程数不超过该主机可用插槽数),调度过程相对简单,会按照插槽轮询或节点轮询的方式进行调度。但若处于超额订阅状态,问题就会变得复杂得多——请继续阅读下文。
更完整的回答是:Open MPI通过从mpirun命令行上的每个应用程序询问两个问题来将进程调度到节点:
需要启动多少个进程?
这些进程应该在哪里启动?
"需要多少个进程"这个问题可以直接通过-n参数传递给mpirun来指定。如果在mpirun命令行中没有指定-n参数,其默认值将是所有节点上插槽(slots)的总和。
“在哪里”这个问题稍微复杂一些,取决于三个因素:
最终的节点列表(例如,经过
-hostname/--host的排除或包含处理之后)调度策略(适用于单个作业中的所有应用程序)
每个主机上的默认和最大槽位数
Open MPI 目前支持两种调度策略:按槽位和按节点:
按槽位分配: 这是默认的调度策略,也可以通过使用
--map-by slot选项传递给mpirun,或将MCA参数rmaps_default_mapping_policy设置为字符串slot来显式请求。在此模式下,Open MPI会在节点上调度进程,直到其所有默认槽位耗尽后才会转移到下一个节点。用MPI术语来说,这意味着Open MPI尝试在不超额订阅主机的情况下,最大化
MPI_COMM_WORLD中相邻等级在同一主机上的数量。例如:
shell$ cat my-hosts node0 slots=2 max_slots=20 node1 slots=2 max_slots=20 shell$ mpirun --hostfile my-hosts -n 8 --map-by slot hello | sort Hello World I am rank 0 of 8 running on node0 Hello World I am rank 1 of 8 running on node0 Hello World I am rank 2 of 8 running on node1 Hello World I am rank 3 of 8 running on node1 Hello World I am rank 4 of 8 running on node0 Hello World I am rank 5 of 8 running on node0 Hello World I am rank 6 of 8 running on node1 Hello World I am rank 7 of 8 running on node1
按节点分配: 可以通过在
mpirun中使用--map-by node选项,或将MCA参数rmaps_default_mapping_policy设置为字符串"node"来请求此策略。在此模式下,Open MPI将以轮询方式在每个节点上调度单个进程(必要时循环回到节点列表开头),直到所有进程都被调度完毕。一旦节点的默认槽位数量耗尽,将跳过该节点。
例如:
shell$ cat my-hosts node0 slots=2 max_slots=20 node1 slots=2 max_slots=20 shell$ mpirun --hostname my-hosts -n 8 --map-by node hello | sort Hello World I am rank 0 of 8 running on node0 Hello World I am rank 1 of 8 running on node1 Hello World I am rank 2 of 8 running on node0 Hello World I am rank 3 of 8 running on node1 Hello World I am rank 4 of 8 running on node0 Hello World I am rank 5 of 8 running on node1 Hello World I am rank 6 of 8 running on node0 Hello World I am rank 7 of 8 running on node1
在这两种策略中,如果所有节点上的默认槽位数量耗尽,而仍有进程需要调度,Open MPI将触发超额订阅状态。
如果将:OVERSUBSCRIBE作为修饰符添加到--map-by选项中(例如mpirun --map-by node:OVERSUBSCRIBE ... — 详见此章节获取更多详情),Open MPI会继续循环遍历节点列表,并尝试在每个节点上再调度一个进程,直到所有进程都被调度完毕。在此过程中,如果节点的最大槽位数已耗尽,则会跳过该节点。如果在所有节点的最大槽位数都已耗尽时仍有进程需要调度,Open MPI将中止运行且不会启动任何进程。
如果未指定:OVERSUBSCRIBE且出现过载情况,Open MPI将在不启动任何进程的情况下中止。
10.4.2. 使用 --hostfile 选项进行调度
--hostfile选项用于mpirun命令,它接受一个文件名参数,该文件列出了要启动MPI进程的主机。
重要
主机文件中列出的主机与MPI通信所使用的网络接口毫无关联。它们仅用于指定在哪些主机上启动MPI进程。
主机文件是简单的文本文件,其中逐行指定了主机列表。每台主机还可以指定默认和最大槽位数量(即该节点上可启动的最大进程数)。文件支持注释内容,空行会被自动忽略。例如:
# This is an example hostfile. Comments begin with #.
#
# Since no slots are specified, the number of slots defaults to the
# number of processor cores available on the machine.
foo.example.com
# We want to allow launching a maximum of 2 processes on this host
# (e.g., potentially because it has two processor cores):
bar.example.com slots=2
关于插槽的更详细讨论,请参阅本节内容。
主机文件以两种不同的方式工作:
排他性: 如果运行主机列表已由其他来源提供(例如通过主机文件或批处理调度程序如Slurm、PBS/Torque、SGE等),则主机文件中指定的主机必须位于已提供的列表中。若主机文件指定的节点不在已有主机列表中,
mpirun将中止运行且不启动任何进程。这种情况下,主机文件起到排他性过滤器的作用——它们会从原始主机列表中限定进程调度范围,最终生成一个经过筛选的主机列表。
例如,假设调度任务包含主机
node01到node04。若运行:shell$ cat my_hosts node03 shell$ mpirun -n 1 --hostfile my_hosts hostname
这将在主机
node03上运行单例hostname命令。但假设您的任务仅分配到
node03,而您运行以下命令:shell$ cat my_hosts node17 shell$ mpirun -n 1 --hostfile my_hosts hostname
这将引发错误(因为
node17未分配给您的任务),mpirun会中止运行。最后请注意,在排他模式下,进程仅会在主机文件指定的主机上执行。如果这导致资源超额分配的情况,默认情况下
mpirun会中止运行。包含性: 如果其他来源未提供主机列表,则通过
--hostfile选项提供的主机将作为初始和最终主机列表使用。在这种情况下,
--hostfile充当包含性智能体;所有由--hostfile提供的主机都可用于进程调度。例如(假设您不处于节点列表被透明提供的调度环境中):shell$ cat my_hosts node01.example.com slots=1 node02.example.com slots=1 node03.example.com slots=1 shell$ mpirun -n 3 --hostfile my_hosts hostname
这将在主机
node01.example.com、node02.example.com和node03.example.com上各启动一个hostname进程副本。
请注意,--hostfile本质上是一个针对每个应用程序的开关选项。
因此,如果您指定多个应用程序(例如在MPMD作业中),
可以多次指定--hostfile参数:
shell$ cat hostfile_1
node01.example.com
shell$ cat hostfile_2
node02.example.com
shell$ mpirun -n 1 --hostfile hostfile_1 hostname : -n 1 --hostfile hostfile_2 uptime
node01.example.com
06:11:45 up 1 day, 2:32, 0 users, load average: 21.65, 20.85, 19.84
请注意 hostname 是在 node01.example.com 上启动的,
而 uptime 是在 node02.example.com 上启动的。
10.4.3. 使用–host选项进行调度
--host选项用于mpirun,它接受一个以逗号分隔的主机列表来指定运行位置。例如:
shell$ mpirun -n 3 --host a,b,c hostname
将在主机a、b和c上各启动一个hostname副本。具体来说:除非通过:N后缀指定,否则每个主机默认使用1个槽位。例如:
shell$ mpirun --host a,b:2,c:3 hostname
将在a上启动一个hostname副本,在b上启动两个hostname副本,在c上启动三个hostname副本。
关于插槽的更详细讨论,请参阅本节内容。
重要
通过--host选项指定的主机与MPI通信所使用的网络接口完全无关。这些主机仅用于指定在哪些主机上启动MPI进程。
--host 参数有两种不同的工作方式:
排他性: 如果运行主机列表已由其他来源提供(例如通过主机文件或批处理调度程序如Slurm、PBS/Torque、SGE等),则通过
--host选项指定的主机必须位于已提供的主机列表中。如果--host指定的节点不在已提供的主机列表中,mpirun将中止运行且不启动任何进程。在这种情况下,
--host选项起到排他性过滤器的作用——它将进程调度范围从原始主机列表缩小,最终生成一个限定后的主机列表。例如,假设主机文件
my_hosts包含从node1到node4的主机。如果运行:shell$ mpirun -n 1 --hostfile my_hosts --host node3 hostname
这将在主机
node3上运行单个hostname进程。但如果运行:shell$ mpirun -n 1 --hostfile my_hosts --host node17 hostname
这将产生错误(因为
node17未列在my_hosts中);mpirun会中止运行。最后请注意,在排他模式下,进程仅会在
--host指定的主机上执行。如果这导致资源超额分配的情况,默认情况下mpirun将中止运行。包含性: 如果主机列表未通过其他来源提供,那么通过
--host选项指定的主机将被用作初始和最终的主机列表。在这种情况下,
--host充当包含性智能体;所有由--host提供的主机都可用于进程调度。例如(假设您不处于节点列表被透明提供的调度环境中):shell$ mpirun -n 3 --host a,b,c hostname
这将在主机
a、b和c上各启动一个hostname进程副本。
请注意,--host本质上是一个针对每个应用程序的开关参数。
因此,如果您指定多个应用程序(例如在MPMD作业中),
可以多次指定--host参数:
shell$ mpirun -n 1 --host a hostname : -n 1 --host b uptime
这将在主机 a 上运行 hostname,在主机 b 上运行 uptime。
10.4.4. 进程槽位
Slots 是 Open MPI 中表示在给定主机上可以启动多少进程的指标。
Open MPI 会维护给定并行作业中每个主机的槽位数量,默认情况下,不允许在主机上启动超过其槽位数量的进程。
重要
通常将主机上的槽位数设置为小于或等于该主机上的处理器核心数。
但需要明确的是,Open MPI中插槽的概念实际上与主机上的物理处理器核心数量无关。
具体来说:主机上的插槽数量可以少于、等于或超过主机上的处理器核心数量。
如果您希望在主机上运行的进程数超过其插槽数,请参阅关于超额订阅的部分。
10.4.4.1. 计算槽位数量
主机上的插槽数量取决于几个因素:
如果主机由作业调度器(如Slurm、PBS/Torque等)指定,则该作业调度器会指定该主机的槽位数量。
如果主机在主机文件中指定:
如果指定了
slots参数,则该值将用作该主机上的插槽数量。否则:
如果指定了
--map-by :HWTCPUS,则默认槽位数为该主机上的硬件线程数。否则,槽位数量默认设置为该主机上的处理器核心数。
如果主机是通过
--host命令行选项指定的:如果指定了
:N后缀,则N将用作该主机上的插槽数量。否则,默认插槽数量为1。
如果同一主机名被多次指定,当指定了
:N时,该主机的槽位值将增加N;若未指定:N,则槽位值增加1。
警告
用于确定槽位(slot)数量的具体方案在Open MPI的不同主要版本间有所变化。上述描述的方案适用于Open MPI v5.0.x版本。
然而,调度程序很少指定最大槽位数。如果未提供每个节点的最大槽位计数,则默认为"无限"(这意味着如果您要求,Open MPI将超额订阅该节点——有关超额订阅的更多信息,请参阅本节)。
以下是一些示例,均来自非预定环境:
使用主机文件并指定
slots参数。shell$ cat my-hostfile node01.example.come slots=4 shell$ mpirun --hostfile my-hostfile hostname node01 node01 node01 node01
这里启动了4个进程,因为在主机文件中指定了
slots=4。使用主机文件且不指定
slots参数(假设node01.example.com有2个处理器核心):shell$ cat my-hostfile node01.example.come shell$ mpirun --hostfile my-hostfile hostname node01 node01
这会启动2个进程,因为未指定
slots参数,且node02有2个处理器核心。使用
--host:shell$ mpirun --host node01.example.com hostname node01
这会启动1个进程,因为不带
:N后缀的--host参数会使该主机的槽位计数增加1。使用
--host参数并添加:N后缀:shell$ mpirun --host node01.example.com:2 hostname node01 node01
这里启动了2个进程,因为命令行中指定了
:2参数。使用
--host参数并添加:N后缀,同时多次指定同一主机:shell$ mpirun --host node01.example.com:2,node01.example.com hostname node01 node01 node01
这会启动3个进程,因为命令行中指定了
:2,然后又额外指定了一次node01.example.com,将该主机的槽位计数增加到了3。
10.4.5. 节点过载使用
在单个节点上运行的MPI进程数量超过处理器可用数量,这种情况被称为节点的超额订阅。Open MPI支持节点超额订阅,但关键在于如何实现这种配置。
具体来说:关键是要让Open MPI 知道您正在超额订阅节点,否则可能导致严重的性能下降。
重要
遵循这条通用原则非常有益:切勿指定超过可用处理器数量的槽位数。
例如,如果你想在一台拥有2个处理器核心的主机上运行4个进程,那么可以指定只有2个插槽但希望运行4个进程。例如:
# In a hostfile, the number of slots will default to the number of
# processor cores on the host
shell$ cat my-hostfile
localhost
shell$ mpirun -n 4 --hostfile my-hostfile a.out
具体来说:我们强烈建议您不要使用包含slots=4的主机文件(因为只有两个可用的处理器核心)。
需要注意的是,上述命令会执行失败,因为你试图运行4个进程但系统仅提供2个可用槽位。你必须通过--map-by :OVERSUBSCRIBE参数明确告知Open MPI允许超额订阅:
shell$ cat my-hostfile
# For the purposes of this example, explicitly tell Open MPI
# that we have 2 slots on the host.
localhost slots=2
shell$ mpirun -n 4 --hostfile my-hostfile --map-by :OVERSUBSCRIBE a.out
您应该告知Open MPI是否超额订阅的原因(即永远不要指定超过可用处理器核心数量的slots值),是因为Open MPI基本上以两种模式运行其消息传递进度引擎:激进模式和降级模式。
降级模式: 当Open MPI认为处于过载状态时(即运行的进程数超过可用处理器核心数),MPI进程将自动进入降级模式,并频繁将处理器让给其他进程,从而确保所有进程都能取得进展。
注意
请务必查看此FAQ条目,其中描述了降级模式对处理器和内存亲和性的影响。
激进模式: 当Open MPI判断处于精确或低负载状态时(即运行进程数等于或少于可用处理器核心数),MPI进程将自动进入激进模式,这意味着它们永远不会主动将处理器让给其他进程。对于某些网络传输协议,这会导致Open MPI在紧密循环中持续尝试推进消息传递,实际上会阻止其他进程获得任何CPU周期(从而导致这些进程无法取得任何进展)。
例如,在一个拥有双处理器核心的节点上:
shell$ cat my-hostfile
localhost slots=4
shell$ mpirun -n 4 --hostfile my-hostfile a.out
这将导致所有4个MPI进程以激进模式运行, 因为Open MPI认为系统有4个可用的处理器核心。 实际上这是错误的(系统只有2个处理器核心—— 而非4个),可能会导致极其糟糕的性能表现。
10.4.6. 强制启用激进或降级性能模式
MCA参数mpi_yield_when_idle控制MPI进程是运行在激进模式还是降级性能模式。将其设置为0强制启用激进模式;设置为1则强制启用降级模式(参阅此FAQ条目了解如何设置MCA参数)。
请注意,该值仅影响MPI进程在阻塞于MPI库调用时的行为。它不会影响非MPI进程的行为,也不会影响不在MPI库调用中的进程行为。
Open MPI通常会自动设置此参数,除非您确实、绝对、完全确定自己在做什么,否则不建议用户设置此参数。