摘要:
HsaNodeProperties是 KFD 拓扑中信息最密集的结构体,包含 30+ 字段描述一个计算节点的完整特征。本文逐字段解析其语义、CPU/GPU 节点的差异、以及各字段对上层运行时决策的影响。
前文讲了KFD中如何获取系统拓扑信息,本节关注一个计算节点的整体信息表达。
1. 结构体全貌
源码位置:
libhsakmt/include/hsakmt/hsakmttypes.h
c
typedef struct _HsaNodeProperties {
// ─── 节点类型标识 ───
HSAuint32 NumCPUCores; // CPU 物理核心数(>0 即为 CPU 节点)
HSAuint32 NumFComputeCores; // GPU SIMD 核心总数(>0 即为 GPU 节点)
HSAuint32 NumNeuralCores; // 神经处理单元数(AIE),无则为 0
// ─── 子资源计数 ───
HSAuint32 NumMemoryBanks; // 内存区域数
HSAuint32 NumCaches; // 缓存层级数
HSAuint32 NumIOLinks; // IO 链路数(含推导的间接链路)
// ─── 计算引擎标识 ───
HSAuint32 CComputeIdLo; // CPU 逻辑处理器起始 ID
HSAuint32 FComputeIdLo; // GPU 逻辑处理器起始 ID
// ─── 能力标志 ───
HSA_CAPABILITY Capability; // 能力标志位(见 §2.7)
HSA_CAPABILITY2 Capability2; // 扩展能力标志位
// ─── GPU 微架构参数 ───
HSAuint32 MaxWavesPerSIMD; // 每 SIMD 最大并发 wave 数
HSAuint32 LDSSizeInKB; // 每 CU LDS 大小 (KB)
HSAuint32 GDSSizeInKB; // Global Data Share 大小 (KB)
HSAuint32 WaveFrontSize; // Wave 宽度(通常 64)
HSAuint32 NumShaderBanks; // Shader Engine 数 (array_count)
HSAuint32 NumArrays; // SIMD 阵列数/SE
HSAuint32 NumCUPerArray; // 每阵列 CU 数
HSAuint32 NumSIMDPerCU; // 每 CU 的 SIMD 数(通常 4)
HSAuint32 MaxSlotsScratchCU; // 每 CU 最大 scratch slot 数
// ─── 固件/引擎版本 ───
HSA_ENGINE_ID EngineId; // GPU 微引擎版本标识
HSA_ENGINE_ID OverrideEngineId; // 覆盖的引擎版本(可为 0)
// ─── 设备标识 ───
HSAuint16 VendorId; // PCI Vendor ID(0x1002 = AMD)
HSAuint16 DeviceId; // PCI Device ID
HSAuint32 LocationId; // PCI BDF 编码
HSAuint64 LocalMemSize; // 本地显存大小 (bytes)
HSAuint32 MaxEngineClockMhzFCompute; // GPU 最大时钟 (MHz)
HSAuint32 MaxEngineClockMhzCCompute; // CPU 最大时钟 (MHz)
HSAint32 DrmRenderMinor; // /dev/dri/renderDXX 的 minor 号
// ─── 名称与版本 ───
HSAuint16 MarketingName[HSA_PUBLIC_NAME_SIZE]; // 设备公开名称 (Unicode)
HSAuint8 AMDName[HSA_PUBLIC_NAME_SIZE]; // CAL 名称 (ASCII)
HSA_ENGINE_VERSION uCodeEngineVersions; // 微码引擎版本
HSA_DEBUG_PROPERTIES DebugProperties; // 调试属性
// ─── XGMI / Hive ───
HSAuint64 HiveID; // XGMI Hive 标识(PSP 哈希)
HSAuint32 NumSdmaEngines; // PCIe 方向 SDMA 引擎数
HSAuint32 NumSdmaXgmiEngines; // XGMI 方向 SDMA 引擎数
// ─── 其他硬件参数 ───
HSAuint8 NumSdmaQueuesPerEngine; // 每 SDMA 引擎队列数
HSAuint8 NumCpQueues; // CP 硬件队列数
HSAuint8 NumGws; // GWS barrier 数
HSAuint8 Integrated; // 0=独立 GPU, 1=集成 GPU
HSAuint32 Domain; // PCI 域
HSAuint64 UniqueID; // 全局唯一不可变 ID(熔丝写入)
// ─── 寄存器文件 ───
HSAuint32 VGPRSizePerCU; // 每 CU VGPR 大小 (bytes)
HSAuint32 SGPRSizePerCU; // 每 CU SGPR 大小 (bytes)
// ─── 多 XCC 与系统信息 ───
HSAuint32 NumXcc; // XCC(Accelerated Compute Die)数
HSAuint32 KFDGpuID; // KFD 生成的 GPU 哈希 ID
HSAuint32 FamilyID; // GPU 家族 ID
// ─── CWSR ───
HSAuint32 CwsrSize; // CWSR 区域大小
HSAuint32 CtlStackSize; // 控制栈大小
// ─── Windows 标识 ───
HSAuint32 LuidLowPart; // Windows LUID 低 32 位
HSAuint32 LuidHighPart; // Windows LUID 高 32 位
HSAuint64 WallClockKHz; // 墙钟频率 (KHz)
} HsaNodeProperties;
内容比较多,不用去死记,还是从前文给出的描述HSA系统的几个维度去理解为什么y有这些字段即可。而且ROCm的更新速度很快,我基于的版本可能与你看到的有些小差异。下面从几个维度解释下关键字段。
2. 字段分组详解
2.1 节点类型判断
c
bool is_cpu_node = (props.NumCPUCores > 0);
bool is_gpu_node = (props.NumFComputeCores > 0);
| 场景 | NumCPUCores | NumFComputeCores | 说明 |
|---|---|---|---|
| 纯 CPU 节点 | 64 | 0 | 典型 EPYC |
| 纯 GPU 节点 | 0 | 15360 | 典型 MI250X |
| APU | >0 | >0 | CPU 和 iGPU 共存于同一节点(少见,通常拆分为两个 Node) |
注意 :NumFComputeCores 不是 CU 数,而是 SIMD 总数 × WaveFrontSize:
NumFComputeCores = NumSIMD × WaveFrontSize
= (128 CU × 4 SIMD/CU) × 64
= 32768 (MI250X 单 die)
2.2 GPU 微架构参数
这组字段完整描述了 GPU 的计算层次结构:
GPU
├── Shader Engine (NumShaderBanks 个)
│ └── SIMD Array (NumArrays 个/SE)
│ └── CU (NumCUPerArray 个)
│ └── SIMD (NumSIMDPerCU 个, 通常 4)
│ └── Wave (MaxWavesPerSIMD 个并发)
│ └── Lane (WaveFrontSize 个, 通常 64)
sysfs 字段对应关系:
| sysfs key | 结构体字段 | 典型值 (MI250X) |
|---|---|---|
array_count |
NumShaderBanks | 8 |
simd_arrays_per_engine |
NumArrays | 2 |
cu_per_simd_array |
NumCUPerArray | 8 |
simd_per_cu |
NumSIMDPerCU | 4 |
simd_count |
NumFComputeCores (换算) | 512 (SIMD 总数) |
max_waves_per_simd |
MaxWavesPerSIMD | 10 |
wave_front_size |
WaveFrontSize | 64 |
lds_size_in_kb |
LDSSizeInKB | 64 |
max_slots_scratch_cu |
MaxSlotsScratchCU | 32 |
上层用途:ROCr runtime 用这些参数计算 dispatch 的 workgroup 限制、scratch 空间分配、occupancy 等。
2.3 设备标识
| 字段 | 说明 | 示例 |
|---|---|---|
| VendorId | PCI 厂商 ID | 0x1002 (AMD) |
| DeviceId | PCI 设备 ID | 0x7388 (MI210) |
| LocationId | PCI BDF 编码 | 0x0300(Bus 3, Dev 0, Func 0) |
| DrmRenderMinor | DRM 渲染节点编号 | 128 → /dev/dri/renderD128 |
| UniqueId | GPU 全局唯一 ID | XGMI hive 内区分相同型号的不同 GPU |
DrmRenderMinor 的作用:
- libhsakmt 只负责 KFD 接口(
/dev/kfd) - 上层的 amdgpu/DRM 操作需要对应的 render node
- 通过
DrmRenderMinor将 KFD 节点映射到 DRM 设备
这就是libhsakmt 看起来是打开了一个/dev/kfd字符设备,但后面是遍历了所有的GPU计算节点,实际上是打开了/dev/dri/renderDXX。这也是一个需要理解的点,有些IOCTL下去后,会走到drm设备上。
UniqueId 的场景:
- XGMI hive 中多个同型号 GPU,DeviceId 相同
UniqueId是物理芯片级别的唯一标识(熔丝写入)- 用于多 GPU 通信时精确路由
2.4 LocationId 编码
LocationId 编码了 PCI 拓扑位置:
LocationId = (Domain << 32) | (Bus << 8) | (Device << 3) | Function
示例: LocationId = 0x0300
Bus = 3
Device = 0
Function = 0
→ PCI 地址 0000:03:00.0
上层通过 LocationId 可以:
- 确定 GPU 挂在哪个 PCIe root complex 下
- 推断 NUMA 亲和性(同一 root complex 通常对应同一 NUMA node)
- 关联
/sys/bus/pci/devices/下的设备信息
2.5 时钟与内存
| 字段 | 说明 | 单位 |
|---|---|---|
| MaxEngineClockMhzFCompute | GPU 核心最大时钟 | MHz |
| MaxEngineClockMhzCCompute | CPU 最大时钟 | MHz |
| LocalMemSize | GPU 本地显存 | bytes |
LocalMemSize 注意事项:
- 这是物理 VRAM 总量,不是可分配量(需减去保留区域)
- 对 CPU 节点,此字段为 0(CPU 内存通过 MemoryProperties 描述)
- MI250X 双 die 配置时,每个 Node 报告单 die 的 VRAM(如 64GB/die)
2.6 SDMA 引擎
NumSdmaEngines = 2 (通用 SDMA,用于 CPU↔GPU、GPU local copy)
NumSdmaXgmiEngines = 3 (XGMI 专用 SDMA,用于 GPU↔GPU 跨 XGMI)
为什么分开:
- XGMI SDMA 直接连接到 XGMI 物理链路,不走 PCIe
- 通用 SDMA 负责 PCIe 方向的传输
- 队列分配时需要根据传输方向选择正确的引擎
2.7 Capability 标志位
HSA_CAPABILITY 在源码中定义为 union + bitfield 结构:
c
typedef union {
HSAuint32 Value;
struct {
unsigned int HotPluggable : 1; // 节点可热插拔
unsigned int HSAMMUPresent : 1; // 存在 IOMMU(ATS/PRI 1.1)
unsigned int SharedWithGraphics : 1; // GPU 同时用于 OS 图形渲染
unsigned int QueueSizePowerOfTwo : 1; // 队列大小须为 2 的幂
unsigned int QueueSize32bit : 1; // 队列大小 < 4GB
unsigned int QueueIdleEvent : 1; // 支持队列空闲通知
unsigned int VALimit : 1; // VA 范围受限(如 40bit)
unsigned int WatchPointsSupported: 1; // 支持硬件断点
unsigned int WatchPointsTotalBits: 4; // 断点数 = 2^value
unsigned int DoorbellType : 2; // Doorbell 版本(0=pre-1.0, 1=1.0, 2=2.0)
unsigned int AQLQueueDoubleMap : 1; // 队列环形缓冲双映射
unsigned int DebugTrapSupported : 1; // GPU 调试陷阱
unsigned int WaveLaunchTrapOverrideSupported: 1;
unsigned int WaveLaunchModeSupported: 1;
unsigned int PreciseMemoryOperationsSupported: 1;
unsigned int DEPRECATED_SRAM_EDCSupport: 1;
unsigned int Mem_EDCSupport : 1; // HBM ECC 功能
unsigned int RASEventNotify : 1; // RAS 事件通知
unsigned int ASICRevision : 4; // ASIC 版本号
unsigned int SRAM_EDCSupport : 1; // SRAM ECC 功能
unsigned int SVMAPISupported : 1; // SVM API 支持
unsigned int CoherentHostAccess : 1; // 主机可一致性访问设备内存
unsigned int DebugSupportedFirmware : 1; // 固件支持 GPU 调试
unsigned int PreciseALUOperationsSupported : 1;
unsigned int PerQueueResetSupported : 1; // 单队列重置
} ui32;
} HSA_CAPABILITY;
关键标志位分组:
| 类别 | 标志位 | 影响 |
|---|---|---|
| 队列特性 | QueueSizePowerOfTwo, AQLQueueDoubleMap, QueueIdleEvent | 队列创建与管理 |
| 调试支持 | DebugTrapSupported, WaveLaunchTrapOverrideSupported, PreciseMemoryOperationsSupported | 调试器功能可用性 |
| 内存/MMU | HSAMMUPresent, VALimit, SVMAPISupported, CoherentHostAccess | 内存模型与 SVM 能力 |
| Doorbell | DoorbellType | 队列通知机制版本 |
| RAS/ECC | Mem_EDCSupport, SRAM_EDCSupport, RASEventNotify | 错误检测与纠正 |
| 硬件版本 | ASICRevision | 同一 DeviceId 下区分具体 stepping |
3. CPU 节点 vs GPU 节点的字段差异
| 字段 | CPU 节点 | GPU 节点 |
|---|---|---|
| NumCPUCores | 64 | 0 |
| NumFComputeCores | 0 | 32768 |
| WaveFrontSize | 0 | 64 |
| LDSSizeInKB | 0 | 64 |
| VendorId | 0 | 0x1002 |
| DeviceId | 0 | 0x7388 |
| DrmRenderMinor | 0 | 128 |
| LocalMemSize | 0 | 17163091968 |
| NumSdmaEngines | 0 | 2 |
| Capability | 0 | 0x3300 |
| MaxEngineClockMhzFCompute | 0 | 1700 |
| MaxEngineClockMhzCCompute | 3500 | 0 |
| NumXcc | 0 | 1 (或多 XCC 时 >1) |
| Integrated | 0 | 0 (独立) / 1 (集成) |
4. 字段与上层决策的关联
| 上层决策 | 依赖的字段 | 决策逻辑 |
|---|---|---|
| 选择目标 GPU | DeviceId, LocalMemSize | 匹配用户指定的设备或选最大 VRAM |
| Scratch 分配 | MaxSlotsScratchCU, NumCUPerArray | 计算每个 wave 的 scratch 上限 |
| 队列创建 | NumCpQueues, Capability | 确定可创建的硬件队列数和类型 |
| SDMA 路径选择 | NumSdmaEngines, NumSdmaXgmiEngines | PCIe vs XGMI 方向 |
| 调试器 attach | Capability (bit 13-15) | 判断是否支持 GPU 调试 |
| DRM 交互 | DrmRenderMinor | 打开对应的 /dev/dri/renderDXX |
| XGMI hive 识别 | HiveID, UniqueID | 区分 hive 及 hive 内的不同 GPU |
| Occupancy 计算 | MaxWavesPerSIMD, NumSIMDPerCU, LDSSizeInKB | 估算 kernel 并发度 |
5. sysfs 键名与结构体字段的完整映射
| sysfs key | HsaNodeProperties 字段 |
|---|---|
cpu_cores_count |
NumCPUCores |
simd_count |
NumFComputeCores (换算) |
mem_banks_count |
NumMemoryBanks |
caches_count |
NumCaches |
io_links_count |
NumIOLinks |
cpu_core_id_base |
CComputeIdLo |
simd_id_base |
FComputeIdLo |
max_waves_per_simd |
MaxWavesPerSIMD |
lds_size_in_kb |
LDSSizeInKB |
gds_size_in_kb |
GDSSizeInKB |
num_gws |
NumGws |
wave_front_size |
WaveFrontSize |
array_count |
NumShaderBanks |
simd_arrays_per_engine |
NumArrays |
cu_per_simd_array |
NumCUPerArray |
simd_per_cu |
NumSIMDPerCU |
max_slots_scratch_cu |
MaxSlotsScratchCU |
vendor_id |
VendorId |
device_id |
DeviceId |
location_id |
LocationId |
domain |
Domain |
drm_render_minor |
DrmRenderMinor |
max_engine_clk_fcompute |
MaxEngineClockMhzFCompute |
max_engine_clk_ccompute |
MaxEngineClockMhzCCompute |
local_mem_size |
LocalMemSize |
fw_version |
EngineId |
capability |
Capability |
capability2 |
Capability2 |
unique_id |
UniqueID |
hive_id |
HiveID |
num_sdma_engines |
NumSdmaEngines |
num_sdma_xgmi_engines |
NumSdmaXgmiEngines |
num_sdma_queues_per_engine |
NumSdmaQueuesPerEngine |
num_cp_queues |
NumCpQueues |
num_xcc |
NumXcc |
family_id |
FamilyID |
vgpr_size_per_cu |
VGPRSizePerCU |
sgpr_size_per_cu |
SGPRSizePerCU |
6. 小结
HsaNodeProperties 是理解 KFD 节点能力的一站式数据源。关键认知:
- 类型判断靠 NumCPUCores / NumFComputeCores,不是单独的 type 字段
- GPU 微架构字段构成层次结构:SE → Array → CU → SIMD → Wave → Lane
- 设备标识用于多系统集成:DrmRenderMinor 桥接 KFD 与 DRM,UniqueID 标识物理芯片,HiveID 标识 XGMI hive
- Capability 位域决定可用特性:调试、doorbell 版本、队列优化等
- SDMA 引擎按传输方向分类:通用 vs XGMI 专用
- 多 XCC 支持:NumXcc 标识 chiplet 数量,VGPRSizePerCU/SGPRSizePerCU 描述寄存器资源