Linux PPC NUMA 资源关联性(Associativity)解析:Form 0/Form 1/Form 2 三种格式与设备树实现
【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux
导读
本文基于 Linux 内核源码仓库中的 Documentation/arch/powerpc/associativity.rst 文档,深入讲解 PowerPC(尤其是 pSeries 平台)上 NUMA 资源关联性(Associativity)的完整概念与实现。读者将掌握三种关联性格式(Form 0、Form 1、Form 2)的差异、PAPR 规范通过哪些设备树属性向操作系统传递资源分组信息、Linux 内核如何根据这些属性计算 NUMA 距离,以及 Form 2 中ibm,numa-lookup-index-table与ibm,numa-distance-table的编码格式与距离矩阵推导方法。文章同时结合 arch/powerpc/mm/numa.c 等源码实现,为理解 pSeries/PowerNV 上的 NUMA 拓扑初始化提供从文档到代码的完整对照。
什么是资源关联性(Associativity)
在 PowerPC 平台中,关联性(Associativity)表示将各种平台资源(CPU、内存、IO 等)划分到多个"域"(domain)的集合关系:同一域内的资源彼此之间具有大体相近的平均性能,而域内某些子集之间的性能又优于其与域外资源子集之间的性能,从而形成嵌套的子分组域(sub-grouping domain)。
在 Linux 内核中,这种性能特征最终以NUMA 节点距离(NUMA node distance)的形式呈现:距离越小,表示两个节点间的访问延迟/带宽越优。从平台(固件/Hypervisor)的角度看,这些分组也被称为"域(domains)"。
PAPR(Power Architecture Platform Requirements)接口目前支持三种向 OS 传递资源分组信息的方式,分别称为Form 0、Form 1、Form 2关联性分组:
- Form 0:最古老的格式,只支持 LOCAL 与 REMOTE 两种 NUMA 距离,现已视为弃用(deprecated);
- Form 1:通过
ibm,associativity与ibm,associativity-reference-points两个设备树属性组合计算 NUMA 距离; - Form 2:增加独立的设备树属性直接表达 NUMA 距离,距离计算更灵活,且允许稀疏的主域编号(domainID)。
Hypervisor 如何指示关联性格式
Hypervisor 通过ibm,architecture-vec-5属性告知 OS 当前使用的是哪一种关联性格式。该属性是 PAPR"架构选项向量 5(Option Vector 5)"的一部分:
ibm,architecture-vec-5属性第 5 字节(byte 5)的bit 0指示使用 Form 0 还是 Form 1,值为1表示使用 Form 1 关联性;- 第 5 字节的bit 2用于指示 Form 2 关联性。
在内核源码中,与这些位对应的选项向量宏定义于 arch/powerpc/include/asm/prom.h:
#define OV5_FORM1_AFFINITY 0x0580 /* FORM1 NUMA affinity */ #define OV5_PRRN 0x0540 /* Platform Resource Reassignment */ #define OV5_FORM2_AFFINITY 0x0520 /* Form2 NUMA affinity */内核在启动早期通过 arch/powerpc/kernel/prom_init.c 构造ibm_architecture_vec时同时声明了对 Form 1 与 Form 2 的支持,而固件侧最终实际采用哪种格式,则由 arch/powerpc/platforms/pseries/firmware.c 将 OV5 选项位映射为固件特性(firmware feature):
{FW_FEATURE_FORM1_AFFINITY, OV5_FORM1_AFFINITY}, {FW_FEATURE_FORM2_AFFINITY, OV5_FORM2_AFFINITY},对应的固件特性位定义在 arch/powerpc/include/asm/firmware.h,而内核在 arch/powerpc/mm/numa.c 的find_primary_domain_index()中按优先级判定最终生效的关联性形式:OPAL(PowerNV)平台固定为 Form 1;pSeries 上若固件声明了 Form 2 特性则用 Form 2,否则依次回退 Form 1、Form 0。
Form 0:最简的 LOCAL/REMOTE 二分距离
Form 0 是历史最悠久的关联性格式,仅支持两个 NUMA 距离:LOCAL(本地)与REMOTE(远端)。
在内核通用定义中,include/linux/topology.h 给出了这两个基准距离的默认数值:
#define LOCAL_DISTANCE 10 #define REMOTE_DISTANCE 20对应到 arch/powerpc/mm/numa.c 的__node_distance()实现,当affinity_form == FORM0_AFFINITY时,逻辑极其简单:
else if (affinity_form == FORM0_AFFINITY) return ((a == b) ? LOCAL_DISTANCE : REMOTE_DISTANCE);即:同一节点距离为LOCAL_DISTANCE(10),不同节点一律为REMOTE_DISTANCE(20)。此外,在 Form 0 下ibm,associativity-reference-points属性要求至少有 2 个条目(第一个整数面向 SMP 配置、第二个面向普通 NUMA 配置),不足时内核会打印short ibm,associativity-reference-points警告并放弃(见 arch/powerpc/mm/numa.c)。
由于无法表达中间层级的拓扑距离,Form 0 无法刻画多级分组下的性能差异,因此已被 PAPR 标记为弃用格式。
Form 1:基于关联性列表与参考点的距离计算
Form 1 通过组合使用ibm,associativity与ibm,associativity-reference-points两个设备树属性来确定资源组/域之间的 NUMA 距离。
ibm,associativity:资源的域分组列表
该属性包含一个或多个数字(每个数字是一个domainID),表示资源所处的平台分组域,从最顶层(最粗粒度)到最底层(最细粒度)逐级排列。属性采用prop-encoded-array编码:第一个整数为列表长度 N,其后为 N 个以encode-int编码的 domainID。
ibm,associativity-reference-points:参考点索引
该属性同样包含一个或多个数字(domainID index),表示在关联性列表中的基于 1 的序数(1-based ordinal),即指出关联性数组中的第几个元素是第几级分组的"域 ID"。
参考点列表表达了一个逐级递增的资源分组层级,例如:
{ primary domainID index, secondary domainID index, tertiary domainID index.. }第一个数字指向最显著(最高层)的 NUMA 边界,其后的数字指向逐渐次要的边界,可以有多个 NUMA 层级。
Linux 内核的计算规则
- NUMA 节点 ID 的确定:Linux 内核取主域参考点(primary domainID index)所指位置的 domainID 作为 NUMA 节点 ID。源码中
__associativity_to_nid()(arch/powerpc/mm/numa.c)正是执行primary_domain_index - 1后读取关联性数组中的对应元素作为 nid,并兼容 POWER4 LPAR 用0xffff表示无效节点的历史行为。 - NUMA 距离的计算:内核通过递归比较两个域是否属于同一更高层域来计算机器之间的距离。从最顶层参考点开始逐级向下比较,只要在某一级发现两者属于不同分组(即该级 domainID 不同),就在距离上加倍一次。
对应源码为 arch/powerpc/mm/numa.c:
for (i = 0; i < distance_ref_points_depth; i++) { if (distance_lookup_table[a][i] == distance_lookup_table[b][i]) break; /* Double the distance for each NUMA level */ distance *= 2; }距离从LOCAL_DISTANCE(10)开始,每多一级不匹配就乘以 2。同样的逐级比较逻辑也体现在 CPU 相对距离计算函数__cpu_form1_relative_distance()(arch/powerpc/mm/numa.c)中:两个 CPU 在各级参考点索引处比较关联性值,逐级累加不匹配计数。
Form 1 下,内核在初始化阶段通过initialize_form1_numa_distance()(arch/powerpc/mm/numa.c)将每个节点的各级域 ID 填入distance_lookup_table[MAX_NUMNODES][MAX_DISTANCE_REF_POINTS],供后续距离计算直接查表。
Form 2:独立距离表与稀疏域编号
Form 2 关联性格式通过新增独立的设备树属性直接表达 NUMA 节点距离,使距离计算从参考点索引值中解耦,从而更加灵活:
- 灵活的主域编号:由于距离计算不再依赖
ibm,associativity-reference-points属性中的索引值,Form 2 允许在同一个 domainID index 位置上出现大量不同的主域 ID,用以表示性能/延迟特征各异的资源组,不再受连续编号或固定层级的约束。
Hypervisor 使用ibm,architecture-vec-5属性的第 5 字节bit 2指示启用了 Form 2 关联性。内核通过FW_FEATURE_FORM2_AFFINITY固件特性识别(arch/powerpc/include/asm/firmware.h),并在 arch/powerpc/mm/numa.c 中据此将affinity_form置为FORM2_AFFINITY。
ibm,numa-lookup-index-table:域 ID 索引表
该属性包含一个或多个数字,表示系统中存在的所有 domainID。domainID 在该属性中的偏移量(offset)被用作计算 NUMA 距离时的索引,本文档将其称为域距离偏移(domain distance offset)。
编码格式(prop-encoded-array):先用encode-int编码 domainID 的数量 N,随后是 N 个以encode-int编码的 domainID。
示例:
"ibm,numa-lookup-index-table" = {4, 0, 8, 250, 252}其中第一个元素 4 表示表中有 4 个 domainID(0、8、250、252)。当计算域 8 与系统中其他域的距离时,使用域 8 在该表中的偏移量2。
ibm,numa-distance-table:NUMA 距离表
该属性包含一个或多个数字,表示系统中各资源组/域之间的 NUMA 距离。
编码格式(prop-encoded-array):先用encode-int编码距离值的数量 N,随后是 N 个以encode-bytes编码的距离值。单个距离值的最大可编码值为 255。数量 N 必须等于 m 的平方,其中 m 是ibm,numa-lookup-index-table中 domainID 的数量。
完整的 Form 2 示例
文档给出的完整示例为:
ibm,numa-lookup-index-table = <3 0 8 40>; ibm,numa-distace-table = <9>, /bits/ 8 < 10 20 80 20 10 160 80 160 10>;查找索引表包含 3 个 domainID:0、8、40,因此距离表包含 3² = 9 个距离值,展开为如下 3×3 距离矩阵:
| 0 8 40 --|------------ | 0 | 10 20 80 | 8 | 20 10 160 | 40| 80 160 10可见:
- 0 与 0、8 与 8、40 与 40(对角线)距离为 10,即
LOCAL_DISTANCE; - 0 与 8 互为 20,即
REMOTE_DISTANCE级别; - 40 与 0、8 的距离高达 80/160,属于远距离的"第三级"拓扑;
- 矩阵沿对角线对称,符合距离的对称性。
对应地,节点 0、8、40 可能的ibm,associativity属性为:
{ 3, 6, 7, 0 } { 3, 6, 9, 8 } { 3, 6, 7, 40}配合ibm,associativity-reference-points取{ 0x3 }(指向关联性列表的第 3 个元素,即倒数第二级),内核根据该参考点读取每个资源关联性列表中第 3 个位置的 domainID 作为主域编号:0、8、40,从而与查找索引表对齐。
内核中的 Form 2 初始化流程
initialize_form2_numa_distance_lookup_table()(arch/powerpc/mm/numa.c)负责在启动阶段构建 Form 2 距离矩阵,核心步骤:
- 从
/ibm,opal(PowerNV)、/rtas或根节点/读取ibm,numa-lookup-index-table,其首元素即 domainID 数量max_numa_index; - 将后续的 domainID 依次填入
numa_id_index_table[]; - 读取
ibm,numa-distance-table,首元素为距离值数量,跳过该encode-int头后即为字节流形式的距离值; - 校验
form2_distances_length == max_numa_index * max_numa_index,不满足时打印Wrong NUMA distance information警告并放弃使用该表,回退为"相同节点 LOCAL、不同节点 REMOTE"的保守距离; - 双重循环填充
numa_distance_table[nodeA][nodeB],将稀疏的 domainID 映射为稠密的距离矩阵。
值得注意的边界处理:如果距离表缺失或长度错误,内核仍会将所有numa_distance_table初始值(-1)替换为合理的默认距离,保证系统可以启动。
Form 2 下的距离查询
一旦进入 Form 2 模式,__node_distance()直接查表返回:
if (affinity_form == FORM2_AFFINITY) return numa_distance_table[a][b];同样地,CPU 相对距离__cpu_form2_relative_distance()(arch/powerpc/mm/numa.c)先由两个 CPU 的关联性列表解析出各自的 nid,再查numa_distance_table,并按LOCAL_DISTANCE(≤10)、REMOTE_DISTANCE(≤20)与更远距离三档归类。
此外,Form 2 下所有可能 NUMA 节点的距离信息要求在启动阶段一次性全部提供(见update_numa_distance()中 arch/powerpc/mm/numa.c 的注释与WARN检查),热插拔新增节点时若在距离表中找不到对应条目会触发告警。
稀疏矩阵的紧凑表达优势
ibm,numa-lookup-index-table帮助实现距离矩阵的紧凑表达:由于 domainID 可以稀疏(例如示例中的 0、8、40 之间有大段空洞),如果直接用 domainID 本身作为矩阵下标,距离矩阵会产生大量无意义的空洞。借助查找索引表把稀疏 domainID 压缩为连续的小整数偏移,再用这些偏移索引距离表,即可有效压缩距离信息的存储空间,这正是 Form 2 设计的核心收益之一。
三种格式对比与内核选择逻辑
| 特性 | Form 0 | Form 1 | Form 2 |
|---|---|---|---|
| 状态 | 弃用(deprecated) | 常用 | pSeries 新型格式 |
| 距离种类 | 仅 LOCAL / REMOTE 两种 | 由参考点层级决定,逐级加倍 | 任意值(单值上限 255),由距离表决定 |
| 关键设备树属性 | ibm,associativity-reference-points | ibm,associativity+ibm,associativity-reference-points | 增加ibm,numa-lookup-index-table+ibm,numa-distance-table |
| 主域编号 | 固定索引 | 由参考点索引决定 | 灵活,允许同索引处多个主域 ID |
| 距离表稀疏支持 | 无 | 无 | 通过查找索引表紧凑表达稀疏矩阵 |
ibm,architecture-vec-5指示位 | 默认(bit0=0) | byte5 bit0=1 | byte5 bit2=1 |
内核在 arch/powerpc/mm/numa.c 中定义了三种形式的常量并维护全局affinity_form状态;find_primary_domain_index()依据固件特性按"OPAL→Form 1、Form 2→Form 1→Form 0"的顺序确定最终形式(arch/powerpc/mm/numa.c),随后整个 NUMA 初始化、距离计算与热插拔更新逻辑均围绕该形式分派执行。若关联性形式检测失败(例如缺少ibm,associativity-reference-points),内核会回退到无 NUMA 的单节点模式(NUMA_NO_NODE),保证系统仍可引导。
进一步阅读
- 关联性设备树属性与距离编码的完整规范说明:Documentation/arch/powerpc/associativity.rst
- pSeries NUMA 核心实现(形式判定、距离表初始化、节点映射):arch/powerpc/mm/numa.c
- OV5 选项向量与固件特性定义:arch/powerpc/include/asm/prom.h、arch/powerpc/include/asm/firmware.h
- 启动期架构向量构造与固件特性映射:arch/powerpc/kernel/prom_init.c、arch/powerpc/platforms/pseries/firmware.c
- 通用 NUMA 距离基准值定义:include/linux/topology.h
【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考