3 Punkte von GN⁺ 2025-12-10 | 1 Kommentare | Auf WhatsApp teilen
  • Ausgehend vom Fehlen eines Debuggers, der die GPU-Ausführung stoppen und den Zustand untersuchen kann, beschreibt der Beitrag, wie diese Funktion direkt auf AMD-GPUs implementiert wird
  • Über die DRM-Schnittstelle und libdrm erfolgt die direkte Kommunikation mit der GPU, wobei Kontext-Erstellung, Pufferzuweisung und Befehlsübermittlung schrittweise aufgebaut werden
  • Mit den TBA/TMA-Registern und dem Trap-Handler wird die GPU-Ausführung angehalten und über die Synchronisierung mit der CPU wird das Lesen sowie die Wiederherstellung des Zustands realisiert
  • Durch SPIR-V-Codekompilierung und RADV-Integration wird die reale Shader-Debugging-Umgebung erweitert und die Implementierung von breakpoint·stepping·watchpoint ermöglicht
  • Dieser Ansatz, der die interne Struktur der GPU direkt steuert, zeigt die Machbarkeit eines vollständigen Debuggers für AMD-GPUs und lässt Raum für eine Weiterentwicklung hin zur Vulkan-Integration

Notwendigkeit und Ansatz beim GPU-Debugging

  • Ausgangspunkt ist der Mangel an einem Werkzeug, mit dem sich die GPU-Ausführung wie bei der CPU anhalten und den Zustand prüfen lässt
    • Das parallele Ausführungsmodell der GPU macht das Debugging deutlich komplexer
  • In der AMD ROCm-Umgebung existiert rocgdb, unterstützt jedoch nur einen auf ROCm begrenzten Bereich
  • Basierend auf der Blog-Serie von Marcell Kiss wurde der Versuch unternommen, einen Debugger zu implementieren, der direkt mit der GPU kommuniziert

Direkte Kommunikation mit der GPU

  • Die Funktionsweise des RADV-Treibers wurde analysiert, um zu lernen, wie man direkt mit der GPU kommuniziert
  • Nach dem Öffnen von /dev/dri/cardX wird mit dem KMD (Kernel Mode Driver) verbunden und anschließend amdgpu_device_initialize aufgerufen
  • Mit libdrm werden Kontext-Erstellung (amdgpu_cs_ctx_create) und Pufferzuweisung durchgeführt
    • Es werden zwei Puffer erzeugt: ein Codepuffer und ein Befehls-Puffer
  • Die Puffer werden in den virtuellen Adressraum von GPU und CPU gemappt
    • Das Mapping wird nicht mehr über amdgpu_bo_va_op, sondern über direkte IOCTL-Aufrufe abgewickelt
  • Mit clang und objdump wird Shader-Assembliercode kompiliert und das Binary extrahiert
  • Die GPU-Befehle werden im PM4 Packet-Format aufgebaut, um den Shader-Ausführungsbefehl zu senden

GPU-Traps und Debugfs-Nutzung

  • Der Trap-Handler wird über die RDNA3-ISA-TBA/TMA-Register eingerichtet
    • TBA: Adresse des Trap-Handers
    • TMA: temporäre Speicheradresse für den Trap-Handler
  • Da aus dem Userspace kein direkter Zugriff möglich ist, wird die debugfs-Schnittstelle verwendet
    • Registerzugriff erfolgt über die Datei /sys/kernel/debug/dri/{PCI address}/regs2
    • Register-Schreibzugriffe mit amdgpu_debugfs_regs2_write
  • Mit je einem VMID werden TBA/TMA gesetzt, um den Trap-Handler zu aktivieren
    • Jede VMID unterscheidet einen GPU-Prozesskontext

Implementierung des Trap-Handlers

  • Der Trap-Handler ist ein privilegiertes Shader-Programm, das ausgeführt wird, wenn die GPU auf eine Ausnahme trifft
  • Über das TTMP-Register werden GPU-Zustände (STATUS, EXEC, VCC usw.) gespeichert
  • Mit dem Befehl global_store_addtid_b32 werden Thread-spezifische Registerwerte im Speicher gespeichert
  • Erkennt die CPU, dass die GPU Daten geschrieben hat, wird die GPU mit dem SQ_CMD-Register kurz angehalten
    • Danach analysiert die CPU die Daten und setzt anschließend mit SQ_CMD die GPU-Ausführung wieder in Gang
  • Beim Verlassen des Handlers werden Programmzähler und Registerzustand wiederhergestellt

SPIR-V-Codeausführung und RADV-Integration

  • Statt manueller Assembly wird die Kompilierung von SPIR-V-Code unterstützt
    • Das ACO-Modul von RADV konvertiert SPIR-V in ein GPU-Binary
    • Mit der Umgebungsvariable RADV_FORCE_FAMILY wird ein virtuelles Gerät erzeugt
  • Im null_winsys-Modus von RADV wird nur kompiliert, ohne physischen Hardwarezugriff
  • Aus dem Kompilat werden Shader-Code, Ressourcenkonfiguration und Debug-Informationen extrahiert

Erweiterung der Debugger-Funktionen

  • Stepping: Mit den Bits RSRC1.DEBUG_MODE und RSRC3.TRAP_ON_START wird die Befehl für Befehl-Ausführung gesteuert
  • Breakpoints: Nach der Berechnung der Programmzählerposition auf Basis der Codepufferadresse erfolgt die Trap-Verarbeitung
  • Source Mapping: Mithilfe der Debug-Informationen des ACO-Compilers erfolgt das Mapping der Source-Code-Zeilen
  • Watchpoints: Mittels GPU-Seiten-Schutz oder des SQ_WATCH-Registers ist eine Adressüberwachung möglich
  • Variablennamen- und Typ-Nachverfolgung: In der NIR-Optimierungsstufe von Mesa ist eine verbesserte Weitergabe von Debug-Informationen erforderlich
  • Vulkan-Integration: Auf Basis von RADV ist Frame-basiertes Debugging mit Puffer-, Textur- und Konstanteninformationen möglich

Bonus: Page-Walking-Code im User Mode

  • Ein Beispielcode für Page-Table-Walk-Code für RDNA3 (gfx11)-GPUs wird bereitgestellt
    • Mit enthaltenen PDE/PTE-Strukturdefinitionen und Dekodierfunktionen
    • mit implementiertem Prozess der Umwandlung einer virtuellen in eine physische Adresse
  • Durch das Lesen der Seitentabellenregister pro VMID ist eine Analyse der GPU-Memory-Mapping-Struktur möglich

Fazit

  • Es wird die Machbarkeit einer vollständigen Debugger-Implementierung über Zugriff auf Kernel- und Hardwareebene auf AMD GPUs nachgewiesen
  • Durch den Aufbau einer bidirektionalen Kommunikationsschleife zwischen CPU und GPU wird das Unterbrechen, die Zustandsanalyse und das Fortsetzen während der Ausführung realisiert
  • Mit zukünftiger RADV- und Vulkan-Integration besteht Potenzial für den weiteren Ausbau zu einer entwicklerfreundlichen GPU-Debugging-Umgebung

1 Kommentare

 
GN⁺ 2025-12-10
Hacker-News-Kommentare
  • Zwar nicht AMD, aber Metal bietet wirklich hervorragende Debugger und Entwicklungs-Tools
    Deshalb nutze ich bei GPU-Arbeit immer zuerst Metal und portiere es danach auf andere Systeme
    Die Metal-Debugger-Dokumentation ist einen Blick wert
    Ich bin zwar kein AAA-Spieleentwickler, aber für meine Zwecke war es nahezu perfekt
    Besonders beeindruckend ist die Funktion, formatierte Log-Strings aus Shadern auszugeben, die dann zusammen mit den App-Logs angezeigt werden
    Ich entwickle gerade eine GPU-basierte App, die sowohl Metal als auch OpenGL verwendet, und auf der OpenGL-Seite war es schwer, Tools auf Metal-Niveau zu finden

    • Ich bin Shadern zum ersten Mal begegnet, als ich OpenGL-Grafikcode auf PS5 und Xbox portiert habe
      Beide Plattformen bieten eigene Debugger, und deren Qualität war ziemlich gut
      Am Ende habe ich verstanden, dass Tooling alles ist, wenn man nur noch einen schwarzen Bildschirm sieht
      Ich frage mich, ob man unter Windows bessere Tools bekommt, wenn man statt OpenGL DirectX verwendet
    • Der Metal-Debugger ist wirklich gut gemacht, aber er friert oft ein oder Xcode stürzt ab
      Vor allem beim Umgang mit Compute Shadern funktioniert das Profiling häufig nicht gut
      Es wirkt wie ein Tool, das primär für Grafik entwickelt wurde und bei KI oder großen Buffer-Arbeitslasten noch Grenzen hat
    • Der Metal-Debugger in Xcode ist hervorragend, und auch die Metal-API selbst ist intuitiv
      Für mich passte sie viel besser als OpenGL
      Hast du auf der OpenGL-Seite schon RenderDoc ausprobiert? Für Vulkan/OpenGL ist das das ähnlichste Tool
    • Ich kann der Meinung schwer zustimmen, man solle für GPU-Lernen einen Mac kaufen
      Einen teuren Computer zu kaufen, um eine Metal-exklusive API zu debuggen, ist ineffizient
      Wenn man ernsthaft Grafikprogrammierung lernen will, ist es meiner Meinung nach besser, unter Windows oder Linux DX12 oder Vulkan zu lernen
      Mit Tools wie RenderDoc geht das gut genug
      Metal ist eine gute API, aber seine größte Einschränkung ist, dass es außerhalb der Apple-Plattformen nicht nutzbar ist
    • Metal ist zwar cool, aber ich halte Vendor Lock-in für das Problem
      In Server- oder Spieleumgebungen werden meist AMD- oder Nvidia-GPUs verwendet, daher ist eine Metal-zentrierte Entwicklung nicht besonders praktikabel
  • Für NVIDIA CUDA gibt es mit cuda-gdb ein First-Party-GDB
    Wie die offizielle Dokumentation zeigt, passt es gut zum Thread-Modell von CUDA
    Allerdings ist Single-Stepping nur auf Warp-Ebene möglich

  • Auf NVIDIA-Karten kann man NSight verwenden, und es gibt außerdem RenderDoc, das auf verschiedenen GPUs funktioniert

    • RenderDoc ist eher ein High-Level-Debugger und auch für Performance-Analyse nützlich
      Wenn High-Level-Visualisierungen wie QML oder QSG_VISUALIZE=overdraw fehlen, ist es interessant, eine Szene auf API-Call-Ebene nachzuverfolgen
    • nsys und nvtx sind ebenfalls hervorragende Werkzeuge
      Viele wissen nicht, dass man sie auch ohne GPU verwenden kann
  • Auf die Frage, ob es offizielle Tools für AMD gibt: GDB unterstützt AMD-GPU-Debugging
    Außerdem gibt es Tools wie AMDs UMR,
    Radeon GPU Detective und die
    Radeon Developer Tool Suite

    • Im Blogbeitrag wird außerdem rocgdb erwähnt, ein Debugger für AMD ROCm
  • Hier ist ein selbst gebautes Monitoring-Tool für AMD-GPUs
    Es handelt sich um das Projekt picomon, das ich gebaut habe, um das Problem zu lösen, dass nvtop zu strikt ist und deshalb oft abstürzt

  • Für jede Plattform gibt es eigene Tools, etwa für Metal, CUDA, Pix oder PS/Switch
    Auch deshalb bevorzugen Forschende noch immer CUDA
    Nsight Systems ist eines davon

  • Mich würde interessieren, ob jemand eine 7900 XTX GPU für lokale Inferenz oder Diffusion verwendet
    Ich habe Linux installiert, aber die Karte liegt die meiste Zeit brach, also würde ich sie gern sinnvoll nutzen

    • Ich nutze sie seit einigen Jahren unter Gentoo
      Früher gab es Probleme rund um Python, aber inzwischen ist es stabil genug, dass sogar img2video möglich ist
      Gemessen an 24 GB VRAM ist sie meiner Meinung nach weiterhin die Karte mit dem besten Preis-Leistungs-Verhältnis
      ROCm wurde kürzlich für UX-Verbesserungen umfassend überarbeitet, daher lohnt sich ein Blick auf TheRock
    • Ich habe unter Windows mit einer 7900XT über ollama ein LLM lokal gehostet, und das hat gut funktioniert
      Auch das Modell devstral:24b lief ziemlich schnell
    • Als ich sie kurz nach dem Release gekauft habe, gab es noch Kernel-OOM-Fehler im Zusammenhang mit ROCm
      In ComfyUI funktionierte das meiste gut, aber bei ungewöhnlicheren Aufgaben war es instabil
      Inzwischen soll es stabiler geworden sein
    • Ich habe ähnliche Aufgaben auch mit einer 6800XT ausprobiert; wegen des CUDA-zentrierten Ökosystems ist es etwas umständlich, aber machbar
    • Ich habe Bild- und Textgenerierungsmodelle getestet, und nachdem ich die Standardbibliothek torch durch die ROCm-Version von AMD ersetzt hatte, lief alles problemlos