摘要本文聚焦 KFD Topology 的发现过程——内核如何通过 sysfs 暴露拓扑信息libhsakmt 如何一次性加载为内存快照以及 Node ID 映射、generation_id 等辅助机制。各 Properties 的字段详解见后续专题文档。前文给出了描述异构系统的四个维度本文关注的是KFD 如何将前三个维度计算节点、内存层次、互联拓扑的信息从内核空间暴露给用户态以及 libhsakmt 如何存储这些信息。整个发现流程可以概括为三步内核暴露KFD 驱动将拓扑信息组织为 sysfs 目录树每个实体节点、内存、缓存、链路对应一个properties文件。用户态加载libhsakmt 在初始化时一次性遍历 sysfs将文本键值对解析为类型化的 C 结构体形成内存中的拓扑快照。增量维护通过generation_id检测拓扑变化必要时重建快照。下面从 sysfs 的目录布局开始逐步展开每个环节。1. sysfs 目录结构1.1 信息从哪里来sysfs 中的拓扑目录不是凭空出现的它是 KFD 内核驱动在加载时根据硬件发现结果创建的。信息来源链路如下GPU 硬件寄存器 / VBIOS / ACPI 表 │ ▼ amdgpu 驱动枚举 PCIe 设备读取 GPU 硬件能力 │ ▼ KFD 驱动kfd_topology.c ├── 从 amdgpu 获取 GPU 节点信息CU 数、VRAM 大小、引擎数等 ├── 从 ACPI/NUMA 获取 CPU 节点和互联距离 ├── 从 PCIe 配置空间获取链路带宽/宽度 └── 调用 sysfs API 创建目录和 properties 文件 │ ▼ /sys/devices/virtual/kfd/kfd/topology/ ← 用户态可见内核侧的关键入口kfd_topology_init()— KFD 模块初始化时创建顶层 sysfs 目录kfd_topology_add_device()— 每发现一个 GPU创建对应nodes/{id}/及其子目录mem_banks、caches、io_links、p2p_links各properties文件的内容由驱动将硬件寄存器值、VBIOS 信息转换为key value\n格式的文本1.2 目录布局KFD 驱动在/sys/devices/virtual/kfd/kfd/topology/下暴露完整的拓扑树/sys/devices/virtual/kfd/kfd/topology/ ├── generation_id # 拓扑版本号uint32任何拓扑变化时递增 ├── system_properties # 系统全局属性键值对文本 │ └── nodes/ ├── 0/ # Node 0 │ ├── properties # 节点核心属性 │ ├── mem_banks/ # 内存区域列表 │ │ ├── 0/properties │ │ └── ... │ ├── caches/ # 缓存层次列表 │ │ ├── 0/properties │ │ └── ... │ ├── io_links/ # IO 链路列表 │ │ ├── 0/properties │ │ └── ... │ └── p2p_links/ # P2P 直连链路 │ ├── 0/properties │ └── ... │ ├── 1/ │ └── ... └── ...设计原则每个 properties 文件都是纯文本键值对key value\n格式目录编号由内核分配可能不连续子目录数量记录在父 properties 中如mem_banks_count 42. sysfs → 数据结构映射总览内容比较多我会分成多个小节来分析。sysfs 路径数据结构详解文档topology/system_propertiesHsaSystemProperties本文topology/nodes/{id}/propertiesHsaNodeProperties03-NodeProperties详解topology/nodes/{id}/mem_banks/{j}/propertiesHsaMemoryProperties[j]04-MemoryProperties详解topology/nodes/{id}/io_links/{j}/propertiesHsaIoLinkProperties[j]05-IoLinkProperties详解topology/nodes/{id}/p2p_links/{j}/propertiesHsaIoLinkProperties[j]05-IoLinkProperties详解topology/nodes/{id}/caches/{j}/propertiesHsaCacheProperties[j]06-CacheProperties详解3. HsaSystemProperties系统级结构体描述整个平台的全局信息typedefstruct_HsaSystemProperties{HSAuint32 NumNodes;// 系统中 KFD 节点总数HSAuint32 PlatformOem;HSAuint32 PlatformId;HSAuint32 PlatformRev;}HsaSystemProperties;对应 sysfssystem_properties: platform_oem 0 platform_id 0 platform_rev 0NumNodes不在文件中直接给出而是通过遍历nodes/目录统计得出。4. 拓扑快照机制4.1 设计思想libhsakmt 不逐次访问 sysfs而是在hsaKmtOpenKFD()时一次性加载全部拓扑信息到内存后续查询直接返回缓存数据。4.2 快照流程hsaKmtOpenKFD() └── topology_take_snapshot() │ ├── 1. 读取 generation_id → 记录当前版本 │ ├── 2. 读取 system_properties → 填充 HsaSystemProperties │ ├── 3. 遍历 nodes/ 目录 │ ├── 统计有效节点数 │ └── 建立 user_id → sysfs_id 映射 │ ├── 4. 对每个节点 i │ ├── 读取 properties → HsaNodeProperties[i] │ ├── 读取 mem_banks/*/prop → HsaMemoryProperties[i][] │ ├── 读取 caches/*/prop → HsaCacheProperties[i][] │ ├── 读取 io_links/*/prop → HsaIoLinkProperties[i][] │ └── 读取 p2p_links/*/prop → 合并到 io_links │ └── 5. 间接链路推导 → 补充缺失的节点对连接4.3 Node ID 映射sysfs 中的节点编号由内核分配可能不连续如热插拔后编号不回收。libhsakmt 在步骤3中建立映射数组屏蔽这一问题staticuint32_tmap_user_to_sysfs_node_id[MAX_NODES];// map_user_to_sysfs_node_id[0] 0 (sysfs node 0)// map_user_to_sysfs_node_id[1] 1 (sysfs node 1)// map_user_to_sysfs_node_id[2] 3 (sysfs node 3, 跳过了 2)上层应用始终使用 0, 1, 2, … 的连续编号调用 APIlibhsakmt 内部翻译为实际 sysfs 路径。4.4 快照释放hsaKmtCloseKFD() └── topology_drop_snapshot() ├── 释放所有节点的 MemoryProperties 数组 ├── 释放所有节点的 CacheProperties 数组 ├── 释放所有节点的 IoLinkProperties 数组 ├── 释放 NodeProperties 数组 └── 重置 SystemProperties4.5 generation_id 与重新加载// 检测拓扑是否变化uint32_tcurrent_genread_generation_id();if(current_gen!cached_generation_id){topology_drop_snapshot();topology_take_snapshot();// 重新加载}适用场景GPU 热插拔、驱动重载等。实际上大多数系统中拓扑在启动后不变。5. sysfs 文件解析实现5.1 解析模式所有 properties 文件采用统一的解析方式// 伪代码FILE*ffopen(/sys/.../nodes/0/properties,r);while(fscanf(f,%s %llu,key,value)2){if(strcmp(key,cpu_cores_count)0)node-NumCPUCoresvalue;elseif(strcmp(key,simd_count)0)node-NumFComputeCoresvalue;// ... 逐字段匹配}5.2 容错处理未知字段跳过前向兼容新内核添加的字段缺失字段保持结构体默认值 0文件打开失败标记该节点无效不计入 NumNodes5.3 CPU 节点的额外信息源CPU 节点仅靠 KFD sysfs 信息不完整需补充额外信息源补充内容/proc/cpuinfoCPU 型号、核心频率/sys/devices/system/cpu/cpu*/cache/L1/L2/L3 缓存大小、行大小、关联度ACPI SRAT/SLIT (间接通过 NUMA)NUMA 距离6. 小结机制作用sysfs 目录树内核暴露拓扑的标准接口快照一次加载、多次查询避免重复 I/ONode ID 映射屏蔽内核编号不连续问题generation_id检测拓扑变化触发重加载间接链路推导补全拓扑图提供全连接视图
1.2 HSA的Topology sysfs 布局与发现机制
摘要本文聚焦 KFD Topology 的发现过程——内核如何通过 sysfs 暴露拓扑信息libhsakmt 如何一次性加载为内存快照以及 Node ID 映射、generation_id 等辅助机制。各 Properties 的字段详解见后续专题文档。前文给出了描述异构系统的四个维度本文关注的是KFD 如何将前三个维度计算节点、内存层次、互联拓扑的信息从内核空间暴露给用户态以及 libhsakmt 如何存储这些信息。整个发现流程可以概括为三步内核暴露KFD 驱动将拓扑信息组织为 sysfs 目录树每个实体节点、内存、缓存、链路对应一个properties文件。用户态加载libhsakmt 在初始化时一次性遍历 sysfs将文本键值对解析为类型化的 C 结构体形成内存中的拓扑快照。增量维护通过generation_id检测拓扑变化必要时重建快照。下面从 sysfs 的目录布局开始逐步展开每个环节。1. sysfs 目录结构1.1 信息从哪里来sysfs 中的拓扑目录不是凭空出现的它是 KFD 内核驱动在加载时根据硬件发现结果创建的。信息来源链路如下GPU 硬件寄存器 / VBIOS / ACPI 表 │ ▼ amdgpu 驱动枚举 PCIe 设备读取 GPU 硬件能力 │ ▼ KFD 驱动kfd_topology.c ├── 从 amdgpu 获取 GPU 节点信息CU 数、VRAM 大小、引擎数等 ├── 从 ACPI/NUMA 获取 CPU 节点和互联距离 ├── 从 PCIe 配置空间获取链路带宽/宽度 └── 调用 sysfs API 创建目录和 properties 文件 │ ▼ /sys/devices/virtual/kfd/kfd/topology/ ← 用户态可见内核侧的关键入口kfd_topology_init()— KFD 模块初始化时创建顶层 sysfs 目录kfd_topology_add_device()— 每发现一个 GPU创建对应nodes/{id}/及其子目录mem_banks、caches、io_links、p2p_links各properties文件的内容由驱动将硬件寄存器值、VBIOS 信息转换为key value\n格式的文本1.2 目录布局KFD 驱动在/sys/devices/virtual/kfd/kfd/topology/下暴露完整的拓扑树/sys/devices/virtual/kfd/kfd/topology/ ├── generation_id # 拓扑版本号uint32任何拓扑变化时递增 ├── system_properties # 系统全局属性键值对文本 │ └── nodes/ ├── 0/ # Node 0 │ ├── properties # 节点核心属性 │ ├── mem_banks/ # 内存区域列表 │ │ ├── 0/properties │ │ └── ... │ ├── caches/ # 缓存层次列表 │ │ ├── 0/properties │ │ └── ... │ ├── io_links/ # IO 链路列表 │ │ ├── 0/properties │ │ └── ... │ └── p2p_links/ # P2P 直连链路 │ ├── 0/properties │ └── ... │ ├── 1/ │ └── ... └── ...设计原则每个 properties 文件都是纯文本键值对key value\n格式目录编号由内核分配可能不连续子目录数量记录在父 properties 中如mem_banks_count 42. sysfs → 数据结构映射总览内容比较多我会分成多个小节来分析。sysfs 路径数据结构详解文档topology/system_propertiesHsaSystemProperties本文topology/nodes/{id}/propertiesHsaNodeProperties03-NodeProperties详解topology/nodes/{id}/mem_banks/{j}/propertiesHsaMemoryProperties[j]04-MemoryProperties详解topology/nodes/{id}/io_links/{j}/propertiesHsaIoLinkProperties[j]05-IoLinkProperties详解topology/nodes/{id}/p2p_links/{j}/propertiesHsaIoLinkProperties[j]05-IoLinkProperties详解topology/nodes/{id}/caches/{j}/propertiesHsaCacheProperties[j]06-CacheProperties详解3. HsaSystemProperties系统级结构体描述整个平台的全局信息typedefstruct_HsaSystemProperties{HSAuint32 NumNodes;// 系统中 KFD 节点总数HSAuint32 PlatformOem;HSAuint32 PlatformId;HSAuint32 PlatformRev;}HsaSystemProperties;对应 sysfssystem_properties: platform_oem 0 platform_id 0 platform_rev 0NumNodes不在文件中直接给出而是通过遍历nodes/目录统计得出。4. 拓扑快照机制4.1 设计思想libhsakmt 不逐次访问 sysfs而是在hsaKmtOpenKFD()时一次性加载全部拓扑信息到内存后续查询直接返回缓存数据。4.2 快照流程hsaKmtOpenKFD() └── topology_take_snapshot() │ ├── 1. 读取 generation_id → 记录当前版本 │ ├── 2. 读取 system_properties → 填充 HsaSystemProperties │ ├── 3. 遍历 nodes/ 目录 │ ├── 统计有效节点数 │ └── 建立 user_id → sysfs_id 映射 │ ├── 4. 对每个节点 i │ ├── 读取 properties → HsaNodeProperties[i] │ ├── 读取 mem_banks/*/prop → HsaMemoryProperties[i][] │ ├── 读取 caches/*/prop → HsaCacheProperties[i][] │ ├── 读取 io_links/*/prop → HsaIoLinkProperties[i][] │ └── 读取 p2p_links/*/prop → 合并到 io_links │ └── 5. 间接链路推导 → 补充缺失的节点对连接4.3 Node ID 映射sysfs 中的节点编号由内核分配可能不连续如热插拔后编号不回收。libhsakmt 在步骤3中建立映射数组屏蔽这一问题staticuint32_tmap_user_to_sysfs_node_id[MAX_NODES];// map_user_to_sysfs_node_id[0] 0 (sysfs node 0)// map_user_to_sysfs_node_id[1] 1 (sysfs node 1)// map_user_to_sysfs_node_id[2] 3 (sysfs node 3, 跳过了 2)上层应用始终使用 0, 1, 2, … 的连续编号调用 APIlibhsakmt 内部翻译为实际 sysfs 路径。4.4 快照释放hsaKmtCloseKFD() └── topology_drop_snapshot() ├── 释放所有节点的 MemoryProperties 数组 ├── 释放所有节点的 CacheProperties 数组 ├── 释放所有节点的 IoLinkProperties 数组 ├── 释放 NodeProperties 数组 └── 重置 SystemProperties4.5 generation_id 与重新加载// 检测拓扑是否变化uint32_tcurrent_genread_generation_id();if(current_gen!cached_generation_id){topology_drop_snapshot();topology_take_snapshot();// 重新加载}适用场景GPU 热插拔、驱动重载等。实际上大多数系统中拓扑在启动后不变。5. sysfs 文件解析实现5.1 解析模式所有 properties 文件采用统一的解析方式// 伪代码FILE*ffopen(/sys/.../nodes/0/properties,r);while(fscanf(f,%s %llu,key,value)2){if(strcmp(key,cpu_cores_count)0)node-NumCPUCoresvalue;elseif(strcmp(key,simd_count)0)node-NumFComputeCoresvalue;// ... 逐字段匹配}5.2 容错处理未知字段跳过前向兼容新内核添加的字段缺失字段保持结构体默认值 0文件打开失败标记该节点无效不计入 NumNodes5.3 CPU 节点的额外信息源CPU 节点仅靠 KFD sysfs 信息不完整需补充额外信息源补充内容/proc/cpuinfoCPU 型号、核心频率/sys/devices/system/cpu/cpu*/cache/L1/L2/L3 缓存大小、行大小、关联度ACPI SRAT/SLIT (间接通过 NUMA)NUMA 距离6. 小结机制作用sysfs 目录树内核暴露拓扑的标准接口快照一次加载、多次查询避免重复 I/ONode ID 映射屏蔽内核编号不连续问题generation_id检测拓扑变化触发重加载间接链路推导补全拓扑图提供全连接视图