ROCm rocr-libhsakmt性能跟踪与分析系列10-4:访问权限管理

1. 引言

在前面的文章中,我们已经了解了如何查询计数器属性和注册跟踪会话。本文将探讨访问权限管理机制,即 hsaKmtPmcAcquireTraceAccess()hsaKmtPmcReleaseTraceAccess() 这对API的实现原理和使用场景。

虽然这两个函数在当前实现中相对简单,但它们在性能跟踪框架中扮演着重要的角色,为未来的扩展和多进程协调提供了基础。

2. API 概览

2.1 Acquire - 获取跟踪访问权限

HSAKMT_STATUS HSAKMTAPI hsaKmtPmcAcquireTraceAccess(
    HSAuint32 NodeId,       // 输入:GPU节点ID
    HSATraceId TraceId      // 输入:跟踪会话ID
);

功能

  • 获取对指定跟踪会话的访问权限
  • 验证TraceId和NodeId的有效性
  • 为未来的访问控制预留接口

2.2 Release - 释放跟踪访问权限

HSAKMT_STATUS HSAKMTAPI hsaKmtPmcReleaseTraceAccess(
    HSAuint32 NodeId,       // 输入:GPU节点ID
    HSATraceId TraceId      // 输入:跟踪会话ID
);

功能

  • 释放对指定跟踪会话的访问权限
  • 验证TraceId的有效性
  • 与Acquire配对使用

2.3 返回值

返回值说明
HSAKMT_STATUS_SUCCESS操作成功
HSAKMT_STATUS_INVALID_PARAMETERTraceId为0
HSAKMT_STATUS_INVALID_HANDLETraceId无效(魔数校验失败)
HSAKMT_STATUS_INVALID_NODE_UNITNodeId无效(仅Acquire)

3. 源码实现分析

3.1 hsaKmtPmcAcquireTraceAccess 详解

hsaKmtPmcAcquireTraceAccess()
    ↓
[1] 调试日志输出
    ↓
[2] 验证 TraceId != 0
    ├─ No → 返回 INVALID_PARAMETER
    └─ Yes → 继续
    ↓
[3] TraceId 转换为 perf_trace 指针
    ↓
[4] 验证魔数 (magic4cc)
    ├─ 不匹配 → 返回 INVALID_HANDLE
    └─ 匹配 → 继续
    ↓
[5] 验证 NodeId
    ├─ 无效 → 返回 INVALID_NODE_UNIT
    └─ 有效 → 继续
    ↓
[6] 返回 SUCCESS

3.2 hsaKmtPmcReleaseTraceAccess 详解

hsaKmtPmcReleaseTraceAccess()
    ↓
[1] 调试日志输出
    ↓
[2] 验证 TraceId != 0
    ├─ No → 返回 INVALID_PARAMETER
    └─ Yes → 继续
    ↓
[3] TraceId 转换为 perf_trace 指针
    ↓
[4] 验证魔数 (magic4cc)
    ├─ 不匹配 → 返回 INVALID_HANDLE
    └─ 匹配 → 继续
    ↓
[5] 返回 SUCCESS

4. 魔数验证机制

4.1 魔数的作用

#define HSA_PERF_MAGIC4CC 0x54415348  // ASCII: "HSAT"

struct perf_trace {
    uint32_t magic4cc;  // 总是第一个字段
    // ... 其他字段 ...
};

为什么使用魔数?

  1. 结构完整性检测: 确保内存未被破坏
  2. 类型安全: 验证指针指向正确的结构类型
  3. 调试辅助: 在内存dump中易于识别
  4. 快速失败: 立即发现无效的TraceId

4.2 魔数选择的艺术

0x54415348 的分解:
0x54 = 'T'
0x41 = 'A'
0x53 = 'S'
0x48 = 'H'
→ "TASH" (反向) → "HSAT" (HSA Trace)

好的魔数特征

  • 易于识别(ASCII可读)
  • 不是常见的数值(0x00000000, 0xFFFFFFFF等)
  • 在内存dump中突出显示
  • 有意义的缩写

4.3 魔数验证流程

// 创建时设置魔数
trace->magic4cc = HSA_PERF_MAGIC4CC;

// 使用时验证魔数
if (trace->magic4cc != HSA_PERF_MAGIC4CC) {
    // TraceId无效的可能原因:
    // 1. TraceId从未注册(随机值)
    // 2. 已被Unregister(内存已释放)
    // 3. 内存损坏(缓冲区溢出等)
    // 4. 指针错误(指向错误的内存)
    return HSAKMT_STATUS_INVALID_HANDLE;
}

5. 使用模式与最佳实践

5.1 标准使用模式

HSAKMT_STATUS status;
HSAuint32 nodeId = 0;
HsaPmcTraceRoot traceRoot;

// 1. 注册跟踪
status = hsaKmtPmcRegisterTrace(nodeId, numCounters, counters, &traceRoot);
if (status != HSAKMT_STATUS_SUCCESS) {
    handle_error(status);
    return;
}

// 2. 获取访问权限
status = hsaKmtPmcAcquireTraceAccess(nodeId, traceRoot.TraceId);
if (status != HSAKMT_STATUS_SUCCESS) {
    hsaKmtPmcUnregisterTrace(nodeId, traceRoot.TraceId);
    handle_error(status);
    return;
}

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

// 4. 启动跟踪
status = hsaKmtPmcStartTrace(traceRoot.TraceId, buffer, 
                            traceRoot.TraceBufferMinSizeBytes);

// 5. 执行工作负载
run_gpu_workload();

// 6. 查询数据
status = hsaKmtPmcQueryTrace(traceRoot.TraceId);

// 7. 停止跟踪
status = hsaKmtPmcStopTrace(traceRoot.TraceId);

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

// 9. 注销跟踪
status = hsaKmtPmcUnregisterTrace(nodeId, traceRoot.TraceId);

// 10. 释放缓冲区
free(buffer);

6. 常见错误场景分析

6.1 使用无效的TraceId

// 错误场景1: 使用未初始化的TraceId
HSATraceId traceId;  // 未初始化,包含随机值
hsaKmtPmcAcquireTraceAccess(0, traceId);
// 结果: INVALID_PARAMETER 或 INVALID_HANDLE

// 错误场景2: 使用已注销的TraceId
hsaKmtPmcUnregisterTrace(nodeId, traceId);  // 释放了内存
hsaKmtPmcAcquireTraceAccess(nodeId, traceId);  // 访问已释放的内存
// 结果: 未定义行为(可能崩溃或返回INVALID_HANDLE)

// 错误场景3: 使用错误的NodeId
hsaKmtPmcRegisterTrace(0, ...);  // 在节点0上注册
hsaKmtPmcAcquireTraceAccess(1, traceId);  // 使用节点1
// 结果: 可能成功(当前实现),但逻辑错误

6.2 忘记配对调用

// 错误: Acquire但忘记Release
hsaKmtPmcAcquireTraceAccess(nodeId, traceId);
// ... 使用跟踪 ...
hsaKmtPmcUnregisterTrace(nodeId, traceId);  // 跳过了Release
// 当前影响: 无(未来可能导致资源泄漏)

// 错误: 多次Acquire
hsaKmtPmcAcquireTraceAccess(nodeId, traceId);
hsaKmtPmcAcquireTraceAccess(nodeId, traceId);  // 重复
// 当前影响: 无(未来可能导致问题)

7. 常见问题 FAQ

Q1: 为什么需要显式调用Acquire/Release?

A: 虽然当前实现很简单,但这对API提供了:

  • 清晰的资源管理语义
  • 未来扩展的空间(引用计数、锁等)
  • 与其他HSA实现的一致性
  • 更好的代码可读性

Q2: Acquire失败会影响TraceId吗?

A: 不会。Acquire失败不影响已注册的跟踪会话:

hsaKmtPmcRegisterTrace(...);  // TraceId已创建
hsaKmtPmcAcquireTraceAccess(...);  // 失败
// TraceId仍然有效,可以重试Acquire或直接Unregister

Q3: 可以多次Acquire同一个TraceId吗?

A: 当前可以,但不推荐:

hsaKmtPmcAcquireTraceAccess(nodeId, traceId);  // 第1次
hsaKmtPmcAcquireTraceAccess(nodeId, traceId);  // 第2次 - 当前允许

未来版本可能引入引用计数,要求Release次数匹配Acquire次数。

Q4: Release之后还能使用TraceId吗?

A: 可以,Release不销毁TraceId:

hsaKmtPmcAcquireTraceAccess(nodeId, traceId);
hsaKmtPmcReleaseTraceAccess(nodeId, traceId);
// TraceId仍然有效
hsaKmtPmcAcquireTraceAccess(nodeId, traceId);  // 可以再次Acquire

只有Unregister会销毁TraceId。

Q5: 如果忘记Release会怎样?

A: 当前没有影响,但:

  • 违反了API契约
  • 未来版本可能导致资源泄漏
  • 最佳实践是始终配对调用

12. 总结

本文深入探讨了访问权限管理API:

核心要点

  1. 验证为主: 主要执行TraceId和NodeId的有效性验证
  2. 配对使用: Acquire和Release应该成对调用

使用建议

  • 总是在Start之前调用Acquire
  • 总是在Unregister之前调用Release
  • 进行充分的错误检查

在下一篇文章中,将详细分析 hsaKmtPmcStartTrace()hsaKmtPmcQueryTrace()hsaKmtPmcStopTrace() 的实现,探讨实际的性能数据采集机制和Linux perf_event的集成。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

DeeplyMind

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

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

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

打赏作者

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

抵扣说明:

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

余额充值