11.10. 调优集合操作
Open MPI的coll框架提供了多个实现集体通信的组件,包括:han、libnbc、self、ucc base、hcoll、sync、xhc、accelerator、basic、ftagree、inter、portals4以及tuned。根据Open MPI的编译方式和系统可用硬件,某些组件可能不可用。运行时基于每个组件自报告的优先级进行决策,选择将使用哪个组件。这些优先级可以通过命令行或设置MCA变量的其他常规方式进行调整,从而影响或覆盖组件选择。最终,选择哪个可用组件取决于多种因素,例如底层硬件以及组件是否提供特定的集体操作(因为并非所有组件都实现所有集体操作)。不过,始终有一个后备的base组件,当其他组件未能提供实现时,它会介入并接管。
本节剩余部分将介绍tuned集合组件中可用的调优选项。
11.10.1. 固定、强制与动态决策
Open MPI的tuned集合通信组件有三种运行模式:固定决策、强制算法和动态决策。由于不同的集合算法在不同场景下表现各异,这些模式的目的是在调用集合操作时选择合适的算法。
在固定决策模式下,决策树(本质上是一组嵌套的if-then-else-if代码块,其中内置了通过测量现有集群性能得出的通信和消息大小阈值)会为调用的特定集合操作选择可用算法之一。固定决策是默认模式。如果您的集群硬件与构建决策树时分析的系统相似,固定决策模式可能会表现良好。然而在某些情况下,固定决策规则可能无法达到理想性能。例如,当您的硬件与用于推导固定规则决策树的硬件存在显著差异时。
在动态决策模式下,用户可以通过ASCII编码文件提供一组规则,这些规则会指示tuned组件根据通信器和消息大小为一个或多个集合操作选择算法。对于未提供规则的集合操作,将使用固定决策模式。有关动态决策模式和规则文件的更多详细信息,请参阅Rules File章节。
在强制算法模式下,用户可以通过命令行为特定集合操作指定算法。具体细节请参阅章节强制使用算法。
11.10.2. 强制使用算法
最简单的调优方法是强制tuned集合组件在所有特定集合调用中使用指定算法。这可以通过命令行或设置MCA变量的其他常规方式实现。例如,以下命令行将整个运行中所有MPI_Alltoall调用的算法设置为linear。
shell$ mpirun ... --mca coll_tuned_use_dynamic_rules 1 \
--mca coll_tuned_alltoall_algorithm 1 ...
当以这种方式选择算法时,与该集合操作关联的固定决策规则将被绕过。这是选择集合算法的一种简便方法,在单个通信器且消息大小在运行期间保持静态时最为有效。另一方面,当给定集合操作的消息大小在运行期间变化,或存在不同大小的多个通信器时,此方法的有效性可能会受到限制。规则文件提供了一种更全面灵活的调优方法。对于未在命令行强制指定算法的集合操作,将使用固定决策规则。
11.10.3. 动态决策与规则文件
鉴于针对特定集合操作的最佳算法选择取决于多个仅在运行时才知晓的因素,且其中部分因素可能在单次运行期间动态变化,通过命令行预设算法通常并非有效的调优手段。规则文件提供了一种基于通信器和消息大小在运行时动态选择算法的机制。该规则文件可通过命令行指定,或通过设置MCA变量的其他常规方式配置。文件在初始化阶段被解析,并在此后生效。
shell$ mpirun ... --mca coll_tuned_use_dynamic_rules 1 \
--mca coll_tuned_dynamic_rules_filename /path/to/my_rules.conf ...
加载的规则集随后将用于根据集合操作、通信器大小和消息大小来选择要使用的算法。文件中未指定规则的集合操作将照常使用固定决策规则。
动态调优文件的组织格式如下:
1rule-file-version-2
21 # num of collectives
33 # collective ID
41 # number of comm sizes
5#=====================
664 # comm size
714 # number of rules
8# Bytes alg topo segs reqs
9#----------------------
100 0 0 0 0
11512000 4 0 0 64
121536000 4 0 0 64
133072000 4 0 0 64
146144000 4 0 0 64
1512288000 4 0 0 16
1624576000 4 0 0 16
1749152000 4 0 0 16
1898304000 4 0 0 16
19196608000 4 0 0 8
20393216000 4 0 0 8
21786432000 4 0 0 1
221572864000 4 0 0 1
232621440000 0 0 0 0
规则文件实际上为一个或多个集合操作定义了一个双变量函数,该函数根据给定的通信器和消息大小,返回调用时使用的算法ID。这一机制允许为每个集合操作指定适用于任意消息和通信器大小范围的算法。在构建通信器时,会通过搜索规则表,使用通信器大小来选择一组与该通信器配套使用的消息大小规则。随后当调用集合操作时,会搜索与该通信器关联的消息大小规则。匹配消息大小最接近(小于等于)的规则将指定所采用的算法。消息大小的实际定义取决于具体的集合操作,详见集合操作与算法章节说明。
用户可以根据需要为任意数量的集合操作、通信器大小和消息大小提供规则。只需按需重复相关部分并调整对应的计数参数即可。必须始终为消息大小为零的情况提供一条规则。消息大小规则应按升序排列。消息大小规则中的最后几个参数可能不会被使用,其具体含义取决于集合操作和算法类型。在算法ID之后的规则中,前两个参数topo和segment size是必填项。在文件格式的第2版中,还可以提供第三个参数max requests。要使用第2版功能,需要Open MPI版本至少为v5.0.7。
文件格式版本标识符rule-file-version-N(其中N为大于等于1的整数)应出现在文件首行。若未指定版本标识符,则默认使用版本1格式。要使用max requests参数必须采用版本2或更高格式。Open MPI 5.0.7之前的版本不支持文件格式版本标识符。使用旧版Open MPI时,请勿包含版本标识符,也不要在消息大小规则中使用max requests参数。
11.10.4. 集合操作及其算法
下表列出了由tuned集合组件实现的集合操作及其对应的枚举标识值。在规则文件中指定规则集时,必须使用该标识值。消息大小的定义因集合操作而异,具体说明见表格。每个集合操作可用的算法及其标识符的描述表格已提供链接。
集合通信 |
标识符 |
消息大小 |
|---|---|---|
0 |
数据类型大小 * 通信大小 * 发送缓冲区中的元素数量 |
|
1 |
数据类型大小 * 从每个进程接收的元素数量之和(recvcounts的总和) |
|
2 |
数据类型大小 * 发送缓冲区中的元素数量 |
|
3 |
数据类型大小 * 通信组大小 * 发送给每个进程的元素数量 |
|
4 |
未使用 |
|
6 |
未使用 |
|
7 |
数据类型大小 * 缓冲区中的条目数 |
|
8 |
数据类型大小 * 通信大小 |
|
9 |
数据类型大小 * 通信规模 * 发送缓冲区中的元素数量 |
|
11 |
数据类型大小 * 发送缓冲区中的元素数量 |
|
12 |
数据类型大小 * 分发到每个进程的结果元素数量之和(recvcounts的总和) |
|
13 |
数据类型大小 * 通信大小 * 每块元素计数 |
|
14 |
数据类型大小 * 通信大小 |
|
15 |
数据类型大小 * 发送缓冲区中的元素数量 |
11.10.4.1. 全局收集 (Id=0)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
linear |
… |
2 |
bruck-k-fanout |
… |
3 |
recursive_doubling |
… |
4 |
环形 |
… |
5 |
邻居 |
… |
6 |
two_proc |
… |
7 |
sparbit |
… |
8 |
direct-messaging |
… |
11.10.4.2. Allgatherv (Id=1)
ID |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
默认 |
… |
2 |
bruck |
… |
3 |
ring |
… |
4 |
邻居 |
… |
5 |
two_proc |
… |
6 |
sparbit |
… |
11.10.4.3. 全局归约 (Id=2)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
basic_linear |
… |
2 |
nonoverlapping |
… |
3 |
recursive_doubling |
… |
4 |
ring |
… |
5 |
segmented_ring |
… |
6 |
rabenseifner |
… |
7 |
allgather_reduce |
… |
11.10.4.4. Alltoall (Id=3)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
linear |
启动所有非阻塞的发送/接收对并等待它们完成。 |
2 |
pairwise |
对于通信规模P,实现为P轮阻塞式MPI_Sendrecv |
3 |
modified_bruck |
一种利用网络数据包量化实现O(log)时间复杂度的算法。通常最适合非常小的消息尺寸。 |
4 |
linear_sync |
始终保持N个非阻塞的MPI_Isend/Irecv通信对处于活跃状态。N值由coll_tuned_alltoall_max_requests MCA变量设置。 |
5 |
two_proc |
专为2个rank之间的alltoall操作优化的实现,其他情况下不使用。 |
11.10.4.5. Alltoallv (Id=4)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
basic_linear |
… |
2 |
成对 |
… |
11.10.4.6. 屏障 (Id=6)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
linear |
… |
2 |
double_ring |
… |
3 |
recursive_doubling |
… |
4 |
bruck |
… |
5 |
two_proc |
… |
6 |
tree |
… |
11.10.4.7. 广播 (Id=7)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
basic_linear |
… |
2 |
chain |
… |
3 |
pipeline |
… |
4 |
split_binary_tree |
… |
5 |
binary_tree |
… |
6 |
二项式 |
… |
7 |
knomial |
… |
8 |
scatter_allgather |
… |
9 |
scatter_allgather_ring |
… |
11.10.4.8. Exscan (Id=8)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
linear |
… |
2 |
recursive_doubling |
… |
11.10.4.9. 收集 (Id=9)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
basic_linear |
… |
2 |
binomial |
… |
3 |
linear_sync |
… |
11.10.4.10. 归约操作 (Id=11)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
linear |
… |
2 |
chain |
… |
3 |
管道 |
… |
4 |
binary |
… |
5 |
二项式 |
… |
6 |
in-order_binary |
… |
7 |
rabenseifner |
… |
8 |
knomial |
… |
11.10.4.11. Reduce_scatter (Id=12)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
非重叠 |
… |
2 |
recursive_halving |
… |
3 |
ring |
… |
4 |
butterfly |
… |
11.10.4.12. Reduce_scatter_block (Id=13)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
basic_linear |
… |
2 |
recursive_doubling |
… |
3 |
recursive_halving |
… |
4 |
butterfly |
… |
11.10.4.13. 扫描 (Id=14)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
linear |
… |
2 |
recursive_doubling |
… |
11.10.4.14. 分散操作 (Id=15)
编号 |
名称 |
描述 |
|---|---|---|
0 |
ignore |
使用固定规则 |
1 |
basic_linear |
… |
2 |
binomial |
… |
3 |
linear_nb |
… |