sPAPR 的 NUMA 机制(pseries 机器)
sPAPR 中 NUMA 的工作方式与 ACPI 的系统局部性距离信息表(SLIT)不同。其逻辑见 LOPAPR 1.1 第 15 章“Non Uniform Memory Access (NUMA) Option”。本文对该规范作补充, 详细说明影响 QEMU 在 pseries 中处理 NUMA 的各个要素。
关联性与 ibm,associativity 属性
关联性定义了一组平台资源:相对于组外的各个资源,组内资源具有相近的平均性能 (在本文语境中即距离)。
ibm,associativity 属性的格式取决于 ibm,architecture-vec-5 属性字节 5 的位 0。 位 0 为零的格式已弃用。当前格式的位 0 为一,此时 ibm,associativity 属性通过 一个或多个列表表示平台的物理层次,从最高层分组一直列到最小分组。考虑以下拓扑:
内存M1 ---- 处理器P1 |
----------------- | 插槽 S1 ---|
芯片 C1 | |
| 硬件模块 1 (MOD1)
内存M2 ---- 处理器P2 | |
----------------- | 插槽 S2 ---|
芯片 C2 |
处理器的 ibm,associativity 属性如下:
P1: {MOD1, S1, C1, P1}
P2: {MOD1, S2, C2, P2}
每个可分配资源都有 ibm,associativity 属性。考虑到同一资源可能与平台有多条连接, LOPAPR 规范允许该属性包含多个列表。
相对性能距离与 ibm,associativity-reference-points
ibm,associativity-reference-points 属性是一个数组,用于定义与性能/距离有关的 边界,从而定义平台的 NUMA 层级。
其元素定义也取决于 ibm,architecture-vec-5 属性字节 5 的位 0。位 0 为零的格式同样 已弃用。在当前格式下,ibm,associativity-reference-points 中的每个整数表示 ibm,associativity 数组中从 1 开始的序号(即首个元素为 1)。第一个边界对应用性能 最为重要,后续边界的重要性依次降低。属于相同性能边界的已分配资源,其相对 NUMA 距离应与该边界的重要性相符。同属第一个边界的资源彼此距离最短。后续边界则表示 更大的距离和更低的性能。
沿用前例,以下参考点设置定义了三个 NUMA 层级:
ibm,associativity-reference-points = {0x3, 0x2, 0x1}
第一个 NUMA 层级(0x3)解释为各 ibm,associativity 数组的第三个元素,第二层级 为第二个元素,第三层级为第一个元素。再假设同属第一 NUMA 层级的元素彼此距离为 10, 每升高一个 NUMA 层级,距离翻倍,则第二层级距离为 20,第三层级为 40。 对于处理器 P1 和 P2,NUMA 层级如下:
* ibm,associativity-reference-points = {0x3, 0x2, 0x1}
* P1: associativity{MOD1, S1, C1, P1}
第一 NUMA 层级 (0x3) => associativity[2] = C1
第二 NUMA 层级 (0x2) => associativity[1] = S1
第三 NUMA 层级 (0x1) => associativity[0] = MOD1
* P2: associativity{MOD1, S2, C2, P2}
第一 NUMA 层级 (0x3) => associativity[2] = C2
第二 NUMA 层级 (0x2) => associativity[1] = S2
第三 NUMA 层级 (0x1) => associativity[0] = MOD1
P1 和 P2 同属第三 NUMA 层级 MOD1:两者距离 = 40
改变 ibm,associativity-reference-points 数组,会使同一组关联数组具有不同的 性能距离属性,如下例所示:
* ibm,associativity-reference-points = {0x2}
* P1: associativity{MOD1, S1, C1, P1}
第一 NUMA 层级 (0x2) => associativity[1] = S1
* P2: associativity{MOD1, S2, C2, P2}
第一 NUMA 层级 (0x2) => associativity[1] = S2
P1 和 P2 没有共同的性能边界。由于此 NUMA 配置只有一个层级,
两者距离比第一层级高一个边界,即 20。
假设某个平台认为同一硬件模块中的所有资源均属于相同性能边界,则有:
* ibm,associativity-reference-points = {0x1}
* P1: associativity{MOD1, S1, C1, P1}
第一 NUMA 层级 (0x1) => associativity[0] = MOD0
* P2: associativity{MOD1, S2, C2, P2}
第一 NUMA 层级 (0x1) => associativity[0] = MOD0
P1 和 P2 同属第一层级边界,两者距离为 10。
pseries Linux 客户机如何计算 NUMA 距离
ACPI SLIT 与 LOPAPR 在 NUMA 方面的另一个关键区别是距离的表达方式。SLIT 表提供 相关资源之间的 NUMA 距离值,而 LOPAPR 未规定计算此值的标准方法。每个资源的 ibm,associativity 提供共同性能的层次结构,ibm,associativity-reference-points 数组则指明哪些关联层级具有相关性。
因此,各个操作系统可以自行实现并解释距离。对于 pseries Linux 客户机,每升高一个 NUMA 层级,距离翻倍;最大层级数限制为 MAX_DISTANCE_REF_POINTS = 4 (见内核源码树的 arch/powerpc/mm/numa.c)。由此得到以下距离:
两个资源同属第一 NUMA 层级:10
资源相隔一个 NUMA 层级:20
资源相隔两个 NUMA 层级:40
资源相隔三个 NUMA 层级:80
资源相隔四个 NUMA 层级:160
pseries NUMA 机制
从 QEMU 5.2 开始,pseries 机器在设置客户机 NUMA 拓扑时考虑用户输入。总体设计如下:
ibm,associativity-reference-points 设置为 {0x4, 0x3, 0x2, 0x1},允许根据 NUMA 层级使用 4 个不同的 NUMA 距离值。
ibm,max-associativity-domains 在所有 NUMA 层级支持多个关联域,为用户提供灵活性。
所有资源的 ibm,associativity 随用户输入变化。
这些变化仅对创建时包含多个 NUMA 节点的 pseries-5.2 及更新机器生效,不计入机器 自身创建的 NUMA 节点(例如 NVLink 2 GPU)。如今的传统支持已存在很久,用户一直 看到的 NUMA 距离为 10 和 40(使用 NVLink2 GPU 时还有 80),没有必要改变这些 客户机现有的体验。
为了提供与 x86 用户调整 NUMA 时相似的体验,我们必须遵循 How the pseries Linux guest calculates NUMA distances 中所述的当前 pseries Linux 内核逻辑。因此,需要将用户输入的 NUMA 距离转换为 pseries Linux 内核的输入。
将用户距离转换为内核距离
用户输入的 NUMA 距离可以从 10 到 254。需要将其转换为 Linux 内核使用的值 (10、20、40、80、160)。转换方式如下:
用户距离 11 至 30 解释为 20
用户距离 31 至 60 解释为 40
用户距离 61 至 120 解释为 80
用户距离 121 及以上解释为 160
用户距离 10 保持为 10
采用这种近似方式,是为了避免将其他值取整到本地距离(10),使其专用于第 4 NUMA 层级(该层级仍专属于 node_id)。其他区间由开发者根据用户输入,自行选择相对合理 的范围。这里可以采用其他策略,但最终必须接受一个事实:大量不同的输入值会被转换成 客户机中的相同 NUMA 拓扑。例如,以下用户输入:
0 1 2
0 10 31 120
1 31 10 30
2 120 30 10
以及另一组用户输入:
0 1 2
0 10 60 61
1 60 10 11
2 61 11 10
在内部都会被转换为相同的值:
0 1 2
0 10 40 80
1 40 10 20
2 80 20 10
建议用户在 NUMA 定义中只使用内核支持的值,以免客户机实际看到的拓扑出乎预期。 下文讨论的关联域分配过程本身已经包含不少潜在的意外情况。
关联域如何分配
LOPAPR 允许每个已分配资源拥有多个关联数组(或“字符串”)。这用于表示资源与主板 之间有多条连接;操作系统决定 NUMA 距离时,应选择能够提供最短距离的关联信息。
spapr 实现不支持每个资源多个关联数组,pseries Linux 内核也不支持。我们必须用每个 资源一个关联数组来表示 NUMA 拓扑,这就意味着必须作出选择和取舍。
考虑用户输入的以下 NUMA 拓扑:
0 1 2 3
0 10 40 20 40
1 40 10 80 40
2 20 80 10 20
3 40 40 20 10
所有关联数组的各个关联域都初始化为 NUMA ID:
节点 0:0 0 0 0
节点 1:1 1 1 1
节点 2:2 2 2 2
节点 3:3 3 3 3
如果只考虑节点 0 到其他所有节点的相对距离,可得到每个距离对应的 NUMA 层级匹配点 (参考点为 {0x4, 0x3, 0x2, 0x1}):
0 到 1 的距离为 40(在 0x4 和 0x3 不匹配,在 0x2 匹配)
0 到 2 的距离为 20(在 0x4 不匹配,在 0x3 匹配)
0 到 3 的距离为 40(在 0x4 和 0x3 不匹配,在 0x2 匹配)
根据 NUMA 层级匹配点,将节点 0 的关联域复制到所有其他节点。0 与 1 在 0x2 匹配, 因此将节点 0 的域 0x2 和 0x1 也复制给节点 1,得到:
节点 0:0 0 0 0
节点 1:0 0 1 1
对节点 2 和节点 3 作相同处理,考虑完与节点 0 的全部匹配关系后,关联数组为:
节点 0:0 0 0 0
节点 1:0 0 1 1
节点 2:0 0 0 2
节点 3:0 0 3 3
与节点 0 有关的距离已处理完。对于节点 1,无需再次访问节点 0;节点 1 到 2 的距离 为 80,在 0x1 匹配;1 到 3 的距离为 40,在 0x2 匹配。重复相同逻辑,复制截至 NUMA 层级匹配点的所有域:
节点 0:0 0 0 0
节点 1:1 0 1 1
节点 2:1 0 0 2
节点 3:1 0 3 3
最后一步只分析节点 2 和 3。2 与 3 的期望距离为 20,即在 0x3 匹配:
节点 0:0 0 0 0
节点 1:1 0 1 1
节点 2:1 0 0 2
节点 3:1 0 0 3
内核读取这些数组,为客户机计算出以下 NUMA 拓扑:
0 1 2 3
0 10 40 20 20
1 40 10 40 40
2 20 40 10 20
3 20 40 20 10
注意,这并非用户想要的结果:0 与 3 的期望距离为 40,而计算结果为 20。 这是在 LOPAPR 规范范围内,内核与 QEMU 当前逻辑和实现限制所能提供的结果。
用户可以利用这些知识试验不同输入,以得到期望的 NUMA 拓扑,或尽可能接近期望。 重要的是,预期应与目前能提供的能力相符:得到的是一个近似结果。
实现限制
如上所述,pSeries NUMA 距离逻辑实际上是在近似用户选择。Linux 内核以及 PAPR 本身 都未向 QEMU 提供手段,将用户输入完全映射到客户机实际使用的 NUMA 距离。 由此产生两个显著限制:
不支持非对称拓扑。仅支持节点 A 到 B 的距离始终等于 B 到 A 的 NUMA 拓扑。 不支持任何往返距离不对称的 A-B 节点对。例如,不支持以下拓扑,使用此输入时 pSeries 客户机将无法启动:
0 1
0 10 40
1 20 10
“非传递性”拓扑无法很好地转换给客户机。此类拓扑中,节点 A 到 B 的距离为 X, B 到 C 的距离为 X,但 A 到 C 的距离不是 X。例如:
0 1 2 3
0 10 20 20 40
1 20 10 80 40
2 20 80 10 20
3 40 40 20 10
在上例中,0 到 2 的距离为 20,2 到 3 为 20,但 0 到 3 为 40。
内核始终匹配尽可能短的关联域,而我们尝试保留此前已建立的
节点间关系。因此,节点 0 与 2 的距离为 20,节点 2 与 3
的距离同为 20,会使节点 0 与 3 的距离也变成 20。
传统(5.1 及更早版本)pseries NUMA 机制
使用 QEMU 5.1 及更早版本时,pseries Linux 客户机中看到的 NUMA 距离可概括为:
本地距离,即资源到其自身 NUMA 节点的距离:10
如果是 NVLink GPU 设备,距离:80
其他所有资源,距离:40
pseries Linux 客户机计算 NUMA 距离的方式,直接影响 QEMU 用户调整 NUMA 时的预期。 在 QEMU 5.1 中,pseries 机器使用的默认 ibm,associativity-reference-points 为:
ibm,associativity-reference-points = {0x4, 0x4, 0x2}
第一层级和第二层级相同,均为 0x4;第三层级在提交 a6030d7e0b35 中专门为支持 NVLink GPU 而添加。这意味着,无论设备树中的 ibm,associativity 属性如何创建, pseries Linux 客户机对于 NUMA 距离只会识别三种情况:
资源同属第一 NUMA 层级,距离为 10
第二层级与第一层级相同,因此跳过
所有非 NVLink GPU 的资源保证同属第三 NUMA 层级,距离为 40
NVLink GPU 到其他所有资源的距离为 80
这也意味着,QEMU 命令行中的用户输入不会改变 pseries 机器客户机内部的 NUMA 距离。