- GPU実行を停止して状態を調査できるデバッガーの不足から出発し、AMD GPUでそれを直接実装する工程を解説
- DRMインターフェースとlibdrmを通じてGPUと直接通信し、コンテキスト作成・バッファ割り当て・コマンド送信の流れを段階的に構成
- TBA/TMAレジスタとトラップハンドラを活用してGPU実行を中断し、CPUとの同期を通じて状態を読み取り・復元する構造を構築
- SPIR-VコードのコンパイルとRADV統合により実際のシェーダーデバッグ環境を拡張し、ブレークポイント・ステップ実行・ウォッチポイント機能を実装可能にする
- GPU内部構造を直接制御するこのアプローチは、AMD GPU向けに完全なデバッガーを実装する可能性を実証し、将来的にVulkan統合へと発展させる余地がある
GPUデバッグの必要性とアプローチ
- CPUのようにGPU実行を一時停止して状態を点検できるツールの欠如から出発
- GPUの並列実行モデルはデバッグをはるかに複雑にする
- AMD ROCm環境には
rocgdbが存在するが、ROCm限定の範囲のみをサポート
- Marcell Kissのブログシリーズを参考に、GPUと直接通信するデバッガーの実装を試みた
GPUと直接通信する
- RADVドライバの動作を追跡しながら、GPUと直接通信する方法を学ぶ
/dev/dri/cardXを開き、**KMD(カーネルモードドライバ)**と接続した後、amdgpu_device_initializeを呼び出す
libdrmでコンテキスト作成(amdgpu_cs_ctx_create)およびバッファ割り当てを実行
- バッファをGPU/CPU仮想アドレス空間にマッピング
amdgpu_bo_va_opの代わりに、直接ioctl呼び出しでマッピング処理を行う
clangとobjdumpを使ってシェーダーアセンブリーコードをコンパイルし、バイナリを抽出
PM4 Packet形式でGPU命令を構成し、シェーダー実行命令を送信
GPUトラップとdebugfsの活用
- RDNA3 ISAのTBA/TMAレジスタを使ってトラップハンドラを設定
TBA: トラップハンドラのアドレス
TMA: トラップハンドラ用の一時メモリアドレス
- ユーザー空間から直接アクセスできないため、debugfsインターフェースを利用
/sys/kernel/debug/dri/{PCI address}/regs2ファイル経由でレジスタへアクセス
amdgpu_debugfs_regs2_writeを使ってレジスタ書き込みを実施
- VMIDごとにTBA/TMAを設定してトラップハンドラを有効化
トラップハンドラの実装
- トラップハンドラはGPUが例外に遭遇した際に実行される特権シェーダープログラム
- TTMPレジスタを用いて**GPU状態(STATUS、EXEC、VCCなど)**を保存
global_store_addtid_b32命令でスレッドごとのレジスタ値をメモリへ保存
- CPUはGPUがデータを書き込むとこれを検出し、SQ_CMDレジスタでGPUを一時停止
- その後CPUがデータを分析した後、再びSQ_CMDでGPU実行を再開
- トラップハンドラは復帰時にプログラムカウンタとレジスタ状態を復元
SPIR-Vコード実行とRADV統合
- 手動アセンブリの代わりにSPIR-Vコードコンパイルをサポート
- RADVの
ACOコンパイラを用いてSPIR-VをGPUバイナリへ変換
RADV_FORCE_FAMILY環境変数で仮想デバイスを生成
- RADVの
null_winsysモードで、実ハードウェアにアクセスせずコンパイルだけを実行
- コンパイル結果からシェーダーコード、リソース設定、デバッグ情報を抽出
デバッガー機能の拡張
- ステッピング:
RSRC1.DEBUG_MODE、RSRC3.TRAP_ON_STARTビットを使って命令単位の実行制御
- ブレークポイント: コードバッファのアドレスを基にプログラムカウンタ位置を計算し、トラップ処理
- ソースマッピング: ACOコンパイラのデバッグ情報でソースコード行をマッピング
- ウォッチポイント: GPUページ保護または
SQ_WATCHレジスタを使ってアドレス監視機能を実装可能
- 変数名・型追跡: MesaのNIR最適化段階におけるデバッグ情報伝達の改善が必要
- Vulkan統合: RADV基盤でフレーム単位デバッグを行い、バッファ・テクスチャ・定数情報を活用可能
ボーナス: ユーザーモードページウォーキングコード
- RDNA3(gfx11)GPU向けのページテーブルウォーキングコード例を提示
- PDE/PTE構造体の定義とデコード関数を含む
- 仮想アドレスから物理アドレスへ変換する処理を実装
- VMIDごとのページテーブルレジスタを読み取り、GPUメモリマッピング構造を解析可能
結論
- AMD GPUへのカーネル・ハードウェアレベルアクセスによる完全なデバッガー実装の可能性を実証
- CPUとGPU間の双方向通信ループを構築し、実行停止・状態分析・再開を実現
- 将来的にRADVおよびVulkan統合により、開発者フレンドリーなGPUデバッグ環境へ発展する可能性がある
1件のコメント
Hacker Newsのコメント
AMDではないが、Metal は本当に優れたデバッガと開発ツール群を提供している
そのため私は GPU の作業をするとき、いつもまず Metal を使い、その後ほかのシステムへ移植するやり方を好んでいる
Metal Debugger のドキュメント を参照するとよい
AAA ゲーム開発者ではないが、自分の用途ではほぼ完璧だった
特にシェーダでフォーマット済みのログ文字列を出力すると、アプリのログと一緒に混ざって表示される機能には驚かされた
Metal と OpenGL の両方を使う GPU ベースのアプリを開発中だが、OpenGL 側では Metal レベルのツールを見つけるのが難しかった
両プラットフォームとも 専用デバッガ を提供しており、その品質はかなり良かった
結局、黒い画面しか見えないときはツールがすべてだと気づいた
OpenGL の代わりに DirectX を使えば、Windows でもっと良いツーリングが得られるのか気になる
特に compute shader を扱うときは、プロファイリングがうまくいかないことが多い
グラフィックス中心に設計されたツールなので、AI や大容量バッファ処理にはまだ限界があるようだ
OpenGL よりずっとしっくりきた
OpenGL 側では RenderDoc を試したことはある? Vulkan/OpenGL 向けでは、それが最も近いツールだ
高価なコンピュータを買って Metal 専用 API をデバッグするのは非効率だ
本気でグラフィックスプログラミングを学ぶなら、Windows や Linux で DX12 や Vulkan を学ぶほうがよいと思う
RenderDoc のようなツールを使えば十分可能だ
Metal は良い API だが、Apple プラットフォーム外では使えない点が最大の制約だ
サーバやゲーム環境ではたいてい AMD や Nvidia の GPU を使うので、Metal 中心の開発は実用的ではない
NVIDIA の CUDA には cuda-gdb という純正の GDB がある
公式ドキュメント を見るとわかるように、CUDA のスレッドモデルによく合っている
ただし、単一ステップ実行はワープ単位でしかできない
NVIDIA カードでは NSight が使え、さまざまな GPU で動く RenderDoc もある
QML や QSG_VISUALIZE=overdraw のような高レベル可視化が不足しているとき、API 呼び出し単位でシーンを追跡できるのは興味深い
GPU がなくても使えることを知らない人が多い
AMD 向けの公式ツールはあるのかという質問に対しては、GDB が AMD GPU デバッグ をサポートしている
また、AMD の UMR や
Radeon GPU Detective、
Radeon Developer Tool Suite のようなツールもある
AMD GPU 向けに自作した 監視ツール を共有している
picomon というプロジェクトで、nvtop が厳格すぎて頻繁にクラッシュする問題を解決するために作ったという
Metal、CUDA、Pix、PS/Switch など、各プラットフォームには専用ツールが存在する
こうした理由から、研究者が今でも CUDA を好む 傾向がある
Nsight Systems もその一つだ
7900 XTX GPU を ローカル推論 (inference) や diffusion に使っている人がいるか気になる
Linux を入れたがほとんど遊んでいるので、有効活用したい
以前は Python 関連の問題があったが、最近は安定して img2video までできる
24GB VRAM 基準では、今でも最も コストパフォーマンスの高いカード だと思う
ROCm は最近 UX 改善 のために大規模な改修が入ったので、TheRock を確認してみるとよい
devstral:24b モデルもかなり速く回った
ComfyUI では大半が問題なく動いたが、変わった処理では不安定だった
最近は安定したと聞いている