ROCm rocr-libhsakmt性能跟踪与分析系列10-1:概述

1. 引言

性能分析是优化GPU应用程序的关键环节。ROCm通过hsakmt层提供了完整的性能计数器pmc(Performance Counter)管理机制,允许开发者监控GPU硬件的运行状态,收集性能数据,从而定位性能瓶颈。

本文档作为系列文章的第一篇,将介绍ROCm rocr里的性能跟踪与分析的整体架构、核心概念和典型使用流程。

2. 架构概览

2.1 系统层次结构

ROCm性能跟踪系统采用分层架构:

+-----------------------------------+
|   用户应用层 (User Application)     |
|   - ROCProfiler                    |
|   - 自定义分析工具                  |
+-----------------------------------+
            ↓ HSA API
+-----------------------------------+
|   HSA KMT API Layer               |
|   - hsaKmtPmcGetCounterProperties |
|   - hsaKmtPmcRegisterTrace        |
|   - hsaKmtPmcStartTrace           |
|   - hsaKmtPmcQueryTrace           |
|   - hsaKmtPmcStopTrace            |
+-----------------------------------+
            ↓ ioctl
+-----------------------------------+
|   KFD Driver (Kernel)             |
|   - 性能计数器硬件管理              |
|   - perf_event 子系统集成          |
+-----------------------------------+
            ↓ 硬件接口
+-----------------------------------+
|   GPU 硬件                         |
|   - 各种性能计数器块                |
|     (SQ, TCC, TCP, etc.)          |
+-----------------------------------+

2.2 核心组件

2.2.1 性能计数器块(Performance Counter Block)

GPU硬件包含多个功能模块,每个模块都有自己的性能计数器:

  • CB (Color Buffer): 颜色缓冲区操作计数器
  • DB (Depth Buffer): 深度缓冲区操作计数器
  • SQ (Shader Sequencer): 着色器执行计数器
  • TCC (Texture Cache per Channel): 纹理缓存计数器
  • TCP (Texture Cache per Pipe): 纹理缓存管道计数器
  • MC (Memory Controller): 内存控制器计数器
  • GRBM (Graphics Register Bus Manager): 图形寄存器总线管理器计数器
  • 等20多种不同的硬件块

每个块包含:

  • 多个计数器(Counters): 监控特定硬件事件
  • 并发槽位限制(Concurrent Slots): 同时激活的计数器数量上限
2.2.2 计数器属性

每个性能计数器具有以下属性:

struct HsaCounter {
    HSAuint32 BlockIndex;           // 所属硬件块ID
    HSAuint64 CounterId;            // 计数器ID
    HSAuint32 CounterSizeInBits;    // 计数器位宽
    HSAuint64 CounterMask;          // 计数器掩码
    HsaCounterFlags Flags;          // 标志位
    HSA_PROFILE_TYPE Type;          // 计数器类型
};
2.2.3 跟踪会话(Trace Session)

跟踪会话是性能分析的基本单位,由以下元素组成:

  • TraceId: 唯一标识一个跟踪会话
  • GPU Node: 目标GPU节点
  • Counter Set: 要监控的计数器集合
  • Trace Buffer: 存储采样数据的缓冲区
  • State: 会话状态(STOPPED/STARTED)

3. 核心数据结构

3.1 perf_trace 结构

struct perf_trace {
    uint32_t magic4cc;              // 魔数,用于验证 (0x54415348 = "HSAT")
    uint32_t gpu_id;                // GPU设备ID
    enum perf_trace_state state;    // 跟踪状态
    uint32_t num_blocks;            // 涉及的硬件块数量
    void *buf;                      // 数据缓冲区指针
    uint64_t buf_size;              // 缓冲区大小
    struct perf_trace_block blocks[0]; // 可变长度数组,存储各块信息
};

3.2 perf_trace_block 结构

struct perf_trace_block {
    enum perf_block_id block_id;    // 硬件块ID
    uint32_t num_counters;          // 该块中的计数器数量
    uint64_t *counter_id;           // 计数器ID数组
    int *perf_event_fd;             // perf事件文件描述符数组
};

3.3 内存布局

注册跟踪时,系统分配一块连续内存,布局如下:

+-----------------------------------+ ← trace
|    perf_trace 结构体               |
+-----------------------------------+ ← trace->blocks[0]
|    perf_trace_block 0             |
|    perf_trace_block 1             |
|    ...                            |
|    perf_trace_block N-1           |
+-----------------------------------+ ← counter_id_ptr
|    block 0's counter IDs (uint64) |
|    block 1's counter IDs          |
|    ...                            |
|    block N-1's counter IDs        |
+-----------------------------------+ ← perf_event_fd
|    block 0's perf_event_fds (int) |
|    block 1's perf_event_fds       |
|    ...                            |
|    block N-1's perf_event_fds     |
+-----------------------------------+

4. 典型使用流程

4.1 完整流程图

         开始
          ↓
[1] hsaKmtPmcGetCounterProperties()
  ↓ 查询GPU支持的性能计数器
  | 返回: HsaCounterProperties (包含所有块和计数器信息)
  ↓
[2] 应用层选择要监控的计数器
  ↓
[3] hsaKmtPmcRegisterTrace()
  ↓ 注册计数器集合
  | 验证: 计数器数量 ≤ 并发限制
  | 分配: perf_trace 结构
  | 返回: TraceId
  ↓
[4] hsaKmtPmcAcquireTraceAccess()
  ↓ 获取跟踪访问权限
  | 验证: TraceId 有效性
  ↓
[5] 分配跟踪缓冲区 (TraceBuffer)
  ↓
[6] hsaKmtPmcStartTrace()
  ↓ 启动性能跟踪
  | 操作: ioctl(PERF_EVENT_IOC_ENABLE)
  | 状态: STOPPED → STARTED
  ↓
[7] 执行被测GPU工作负载
  ↓
[8] hsaKmtPmcQueryTrace() (可多次调用)
  ↓ 查询计数器当前值
  | 读取: perf_event_fd 数据
  | 填充: TraceBuffer
  ↓
[9] hsaKmtPmcStopTrace()
  ↓ 停止性能跟踪
  | 操作: ioctl(PERF_EVENT_IOC_DISABLE)
  | 状态: STARTED → STOPPED
  ↓
[10] 分析 TraceBuffer 中的数据
  ↓
[11] hsaKmtPmcReleaseTraceAccess()
  ↓ 释放跟踪访问权限
  ↓
[12] hsaKmtPmcUnregisterTrace()
  ↓ 注销跟踪会话
  | 释放: perf_trace 结构
         ↓
        结束

4.2 流程详细说明

阶段一:准备阶段

步骤1: 查询计数器属性

  • 调用 hsaKmtPmcGetCounterProperties(NodeId, &CounterProperties)
  • 获取GPU节点支持的所有性能计数器信息
  • 系统会缓存结果,后续调用直接返回缓存

步骤2: 选择计数器

  • 应用层根据性能分析需求选择计数器
  • 构造 HsaCounter 数组

步骤3: 注册跟踪

  • 调用 hsaKmtPmcRegisterTrace(NodeId, NumCounters, Counters, &TraceRoot)
  • 系统验证计数器合法性和并发限制
  • 分配并初始化 perf_trace 结构
  • 返回 TraceId 和最小缓冲区大小

步骤4: 获取访问权限

  • 调用 hsaKmtPmcAcquireTraceAccess(NodeId, TraceId)
  • 验证 TraceId 有效性
阶段二:跟踪阶段

步骤5: 分配缓冲区

  • 根据 TraceBufferMinSizeBytes 分配内存
  • 通常使用页对齐的大小

步骤6: 启动跟踪

  • 调用 hsaKmtPmcStartTrace(TraceId, TraceBuffer, BufferSize)
  • 系统通过 ioctl 启用所有 perf 事件
  • 跟踪状态变为 STARTED

步骤7: 执行工作负载

  • 运行需要性能分析的GPU代码
  • GPU执行过程中,硬件计数器持续累加

步骤8: 查询计数器

  • 调用 hsaKmtPmcQueryTrace(TraceId) 读取当前值
  • 可以多次调用以获取时间序列数据
  • 数据写入 TraceBuffer
阶段三:清理阶段

步骤9: 停止跟踪

  • 调用 hsaKmtPmcStopTrace(TraceId)
  • 系统通过 ioctl 禁用所有 perf 事件
  • 跟踪状态变为 STOPPED

步骤10: 分析数据

  • 解析 TraceBuffer 中的性能数据
  • 计算性能指标

步骤11-12: 释放资源

  • 调用 hsaKmtPmcReleaseTraceAccess(NodeId, TraceId)
  • 调用 hsaKmtPmcUnregisterTrace(NodeId, TraceId)
  • 释放 perf_trace 结构和其他资源

5. 关键设计特点

5.1 并发限制验证

每个硬件块都有并发槽位限制,例如:

  • SQ块可能支持16个并发计数器
  • TCC块可能支持4个并发计数器

系统在注册时会验证:

if (num_counters[block_id] > concurrent_limit) {
    return HSAKMT_STATUS_INVALID_PARAMETER;
}

5.2 缓存机制

首次调用 hsaKmtPmcGetCounterProperties() 时,系统查询硬件并缓存结果:

if (counter_props[NodeId]) {
    *CounterProperties = counter_props[NodeId];  // 直接返回缓存
    return HSAKMT_STATUS_SUCCESS;
}

5.3 状态管理

跟踪会话有明确的状态转换:

    STOPPED ←→ STARTED
       ↑          ↓
    [Register]  [Start]
       ↑          ↓
    [Stop]    [Query]

5.4 内存管理策略

  • 单次分配: perf_trace 及其所有子结构在一次 calloc 中分配
  • 连续布局: 所有数据紧密排列,提高缓存友好性
  • 自动清理: Unregister 时自动停止正在运行的跟踪

5.5 错误处理

系统提供多层错误检查:

  1. 魔数验证: 通过 magic4cc 验证 TraceId 有效性
  2. 节点验证: 确保 NodeId 和 gpu_id 匹配
  3. 状态验证: 确保操作在正确的状态下进行
  4. 回滚机制: 部分失败时自动回滚(如 StartTrace 失败)

6. Linux perf_event 集成

ROCm性能跟踪基于Linux的 perf_event 子系统:

// 每个计数器对应一个 perf_event_fd
int perf_event_fd;

// 启用计数器
ioctl(perf_event_fd, PERF_EVENT_IOC_ENABLE, NULL);

// 读取计数值
struct perf_counts_values {
    uint64_t val;   // 计数值
    uint64_t ena;   // 启用时间
    uint64_t run;   // 运行时间
};
read(perf_event_fd, &content, sizeof(content));

// 禁用计数器
ioctl(perf_event_fd, PERF_EVENT_IOC_DISABLE, NULL);

7. 使用场景

7.1 基准测试(Benchmarking)

监控关键性能指标:

  • 内存带宽利用率(通过TCC计数器)
  • 计算单元利用率(通过SQ计数器)
  • 缓存命中率(通过TCP/TCC计数器)

7.2 性能优化

识别瓶颈:

  • 内存瓶颈:高L2缓存未命中率
  • 计算瓶颈:高ALU利用率,低内存访问
  • 同步瓶颈:波前停顿时间长

7.3 功耗分析

监控功耗相关事件:

  • GPU时钟频率
  • 活跃CU数量
  • 内存控制器活动

8. 限制与注意事项

8.1 硬件限制

  • 并发计数器数量: 每个块有固定的并发槽位限制
  • 采样粒度: 计数器通常按波前或时钟周期累加
  • 精度: 硬件计数器可能存在微小误差

8.2 软件限制

  • 单进程: 一个进程独占GPU性能计数器
  • 权限: 某些计数器可能需要特权访问
  • 开销: 频繁查询会引入性能开销

8.3 最佳实践

  1. 最小化计数器数量: 只监控必要的计数器
  2. 批量查询: 减少 QueryTrace 调用频率
  3. 预分配缓冲区: 使用足够大的 TraceBuffer
  4. 错误处理: 始终检查返回值
  5. 资源清理: 确保调用 Unregister 释放资源

9. 示例代码框架

// 1. 查询计数器属性
HsaCounterProperties *props;
hsaKmtPmcGetCounterProperties(nodeId, &props);

// 2. 选择计数器(示例:选择SQ块的2个计数器)
HsaCounter counters[2];
counters[0].BlockIndex = PERFCOUNTER_BLOCKID__SQ;
counters[0].CounterId = 0x1;  // SQ计数器1
counters[1].BlockIndex = PERFCOUNTER_BLOCKID__SQ;
counters[1].CounterId = 0x2;  // SQ计数器2

// 3. 注册跟踪
HsaPmcTraceRoot traceRoot;
hsaKmtPmcRegisterTrace(nodeId, 2, counters, &traceRoot);

// 4. 获取访问权限
hsaKmtPmcAcquireTraceAccess(nodeId, traceRoot.TraceId);

// 5. 分配缓冲区
void *buffer = malloc(traceRoot.TraceBufferMinSizeBytes);

// 6. 启动跟踪
hsaKmtPmcStartTrace(traceRoot.TraceId, buffer, traceRoot.TraceBufferMinSizeBytes);

// 7. 执行GPU工作负载
// ... launch kernels ...

// 8. 查询计数器
hsaKmtPmcQueryTrace(traceRoot.TraceId);

// 9. 分析数据
uint64_t *data = (uint64_t *)buffer;
printf("Counter 0: %lu\n", data[0]);
printf("Counter 1: %lu\n", data[1]);

// 10. 停止跟踪
hsaKmtPmcStopTrace(traceRoot.TraceId);

// 11. 释放访问权限
hsaKmtPmcReleaseTraceAccess(nodeId, traceRoot.TraceId);

// 12. 注销跟踪
hsaKmtPmcUnregisterTrace(nodeId, traceRoot.TraceId);

// 13. 清理
free(buffer);

10. 总结

ROCm性能跟踪与分析系统提供了强大而灵活的GPU性能监控能力:

  • 完整的硬件覆盖: 支持20+种硬件块的性能计数器
  • 标准化接口: 基于HSA标准API
  • Linux集成: 充分利用perf_event子系统
  • 易于使用: 清晰的生命周期管理

在接下来的系列文章中,我们将深入探讨:

  • 第二篇: 性能计数器查询与计数器类型详解
  • 第三篇: 跟踪会话注册与资源管理
  • 第四篇: 跟踪启动、数据采集与停止
  • 第五篇: 数据解析与性能分析方法
  • 第六篇: 高级应用与优化技巧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeeplyMind

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值