文章摘要
作者探讨了GPU调试工具的缺失问题,发现AMD ROCm环境下的rocgdb调试器功能有限。受Marcell Kiss博客启发,作者尝试直接与GPU通信,通过分析RADV驱动和libdrm库,探索在不使用Vulkan的情况下运行基本着色器的方法。
文章总结
AMD GPU调试器开发探索
作者Abdelhadi | عبدالهادي分享了他开发AMD GPU调试器的过程,这是一项旨在为GPU创建类似CPU调试工具的技术探索。
动机与灵感
作者一直困惑为何没有类似CPU调试器的GPU工具,能够暂停执行并检查当前状态。在发现ROCm环境下的rocgdb调试器(功能有限)后,受到Marcell Kiss博客系列的启发,决定自己尝试实现这一功能。
技术实现路径
直接与GPU通信
通过研究RADV(Mesa的Vulkan驱动)代码,作者找到了绕过Vulkan直接运行基础着色器的方法。关键步骤包括:
1. 通过/dev/dri/cardX建立与内核模式驱动(KMD)的连接
2. 使用libdrm库作为用户模式驱动(UMD)和KMD之间的中间层
3. 创建上下文并分配两个缓冲区(代码缓冲区和命令缓冲区)
内存管理
详细实现了缓冲区分配和内存映射逻辑,包括: - 选择内存域(VRAM/GTT)和缓存标志 - 处理GPU和CPU虚拟地址空间的映射 - 解决uncached内存标记问题
命令提交
解释了AMD GPU特有的PM4数据包格式,特别是类型3数据包:
- 通过set_shader_reg数据包配置GPU寄存器
- 实现直接调度命令
- 使用间接缓冲区提交命令到KMD
陷阱处理机制
硬件支持
利用RDNA3架构的TBA/TMA寄存器实现陷阱处理: - TBA存储陷阱处理程序地址 - TMA作为临时存储寄存器 - 通过debugfs接口修改这些特权寄存器
陷阱处理程序
编写了能保存GPU状态的陷阱处理程序: - 使用TTMP寄存器保存关键状态 - 实现CPU-GPU通信协议 - 处理硬件陷阱和软件陷阱的不同返回逻辑
高级调试功能
SPIR-V支持
集成RADV的ACO编译器: - 使用null_winsys模式编译SPIR-V代码 - 获取调试信息和寄存器配置
调试器功能
实现了多项调试功能: - 断点和单步执行:利用RSRC1和RSRC3寄存器中的调试位 - 源码映射:通过ACO生成的调试信息 - 监视点:探索硬件监视寄存器支持 - 变量追踪:改进Mesa的NIR中间表示
未来方向
作者计划: 1. 深度集成RADV驱动获取完整Vulkan信息 2. 改进变量类型和名称支持 3. 实现更完整的页面遍历功能
技术挑战
项目面临的主要挑战包括: - GPU并发执行模型的复杂性 - 缺乏稳定的GPU ABI - 特权寄存器访问限制 - 多波处理问题
这项探索展示了GPU调试器的可行性,为开发者提供了宝贵的底层GPU编程见解。
评论总结
总结评论内容:
- 关于AMD官方工具的询问
- 主要观点:询问是否存在AMD官方工具
- 关键引用: "Is there not an official tool from AMD?"("难道没有AMD的官方工具吗?")
- NVIDIA CUDA调试工具推荐
- 主要观点:推荐使用NVIDIA官方的cuda-gdb工具
- 论据:该工具与GDB线程模型兼容良好
- 关键引用: "There also exists cuda-gdb...I've found it to be pretty good."("还有cuda-gdb...我觉得它相当不错") "it works well with the GDB thread ergonomics"("它与GDB线程人体工学配合良好")
- 其他GPU调试工具建议
- 主要观点:推荐NSight和RenderDoc工具
- 论据:RenderDoc支持多种GPU
- 关键引用: "For NVIDIA cards, you can use NSight."("对于NVIDIA显卡,你可以使用NSight") "There's also RenderDoc that works on a large number of GPUs."("还有支持多种GPU的RenderDoc")
- 关于AMD显卡的利用问题
- 主要观点:询问如何利用闲置的AMD显卡(7900 XTX)
- 关键引用: "is anyone using a 7900 XTX for local inference/diffusion?"("有人在用7900 XTX做本地推理/扩散吗?") "I would love to put this card to work in some capacity."("我很想让这张显卡发挥些作用")