3 points par GN⁺ 2025-12-10 | Aucun commentaire pour le moment. | Partager sur WhatsApp
  • Partant de l'absence d'un débogueur capable d'interrompre l'exécution du GPU et d'en examiner l'état, l'article décrit la mise en œuvre directe de cette capacité sur les GPU AMD.
  • En communiquant directement avec le GPU via l'interface DRM et libdrm, il met en place étape par étape la création de contexte, l'allocation de buffers et l'envoi de commandes.
  • Il construit une architecture qui interrompt l'exécution du GPU avec les registres TBA/TMA et un trap handler, puis lit et restaure l'état grâce à une synchronisation avec le CPU.
  • En intégrant la compilation de code SPIR-V et RADV, l'environnement réel de débogage de shaders est étendu et les fonctions de breakpoint·stepping·watchpoint deviennent implémentables.
  • Cette approche, qui contrôle directement l'architecture interne du GPU, démontre la faisabilité d'un débogueur complet pour GPU AMD et laisse entrevoir une évolution vers une intégration Vulkan.

Besoin et approche du débogage GPU

  • L'approche part du constat qu'il n'existe pas d'outil pour arrêter l'exécution d'un GPU et inspecter son état comme sur un CPU.
    • Le modèle d'exécution parallèle du GPU rend le débogage nettement plus complexe.
  • Un rocgdb existe dans l'environnement AMD ROCm, mais il ne prend en charge qu'une zone limitée à ROCm.
  • En se basant sur la série d'articles de Marcell Kiss, une implémentation d'un débogueur communiquant directement avec le GPU est tentée.

Déboguer en communiquant directement avec le GPU

  • Le fonctionnement du pilote RADV est suivi pour apprendre à communiquer directement avec le GPU.
  • Après ouverture de /dev/dri/cardX, connexion au KMD (kernel-mode driver) puis appel de amdgpu_device_initialize.
  • Avec libdrm, création de contexte (amdgpu_cs_ctx_create) et allocation de buffers.
    • Deux buffers sont créés : un buffer de code et un buffer de commandes.
  • Les buffers sont mappés dans les espaces d'adresses virtuelles GPU/CPU.
    • Le mapping se fait via des appels IOCTL directs au lieu de amdgpu_bo_va_op.
  • Compilation de code assembleur de shader avec clang et objdump, puis extraction du binaire.
  • Construction de commandes GPU au format PM4 Packet pour envoyer les ordres d'exécution des shaders.

Utilisation des traps GPU et de debugfs

  • Les registres TBA/TMA de l'ISA RDNA3 servent à configurer le trap handler.
    • TBA : l'adresse du trap handler
    • TMA : l'adresse mémoire temporaire pour le trap handler
  • L'accès direct depuis l'espace utilisateur étant impossible, il faut utiliser l'interface debugfs.
    • Accès aux registres via le fichier /sys/kernel/debug/dri/{PCI address}/regs2.
    • Écriture des registres via amdgpu_debugfs_regs2_write.
  • Pour chaque VMID, TBA/TMA sont configurés afin d'activer le trap handler.
    • Chaque VMID distingue un contexte de processus GPU.

Implémentation du trap handler

  • Le trap handler est un programme shader privilégié exécuté lorsqu'un GPU rencontre une exception.
  • Les registres TTMP sont utilisés pour stocker l'état du GPU (STATUS, EXEC, VCC, etc.).
  • L'instruction global_store_addtid_b32 écrit en mémoire les valeurs de registres thread par thread.
  • Dès que le CPU détecte que le GPU a écrit les données, il suspend le GPU via le registre SQ_CMD.
    • Le CPU analyse ensuite les données, puis relance le GPU via SQ_CMD.
  • Lors du retour, le trap handler restaure le compteur de programme et l'état des registres.

Exécution SPIR-V et intégration RADV

  • Au lieu de l'assemblage manuel, la compilation de code SPIR-V est prise en charge.
    • Le compilateur ACO de RADV est utilisé pour convertir SPIR-V en binaire GPU.
    • Le périphérique virtuel est créé avec la variable d'environnement RADV_FORCE_FAMILY.
  • En mode null_winsys de RADV, seule la compilation est exécutée, sans accès matériel réel.
  • Des informations de shader, de configuration des ressources et de débogage sont extraites du résultat de compilation.

Extension des fonctionnalités de débogage

  • Stepping : contrôle d'exécution au niveau des instructions via les bits RSRC1.DEBUG_MODE et RSRC3.TRAP_ON_START.
  • Breakpoints : calcul de la position du programmeur en fonction de l'adresse du buffer de code, puis gestion par trap.
  • Source Mapping : mappage des lignes de code source grâce aux informations de débogage du compilateur ACO.
  • Watchpoints : implémentation possible de la surveillance d'adresses via la protection de page GPU ou le registre SQ_WATCH.
  • Suivi des noms et types de variables : besoin d'améliorer la transmission des informations de débogage dans l'étape d'optimisation NIR de Mesa.
  • Intégration Vulkan : basée sur RADV, elle peut exploiter infos buffer, texture et constantes pour un débogage par frame.

Bonus : code de parcours de pages en mode utilisateur

  • Un exemple de code de parcours de table de pages pour GPU RDNA3 (gfx11) est fourni.
    • Définitions de structures PDE/PTE et fonctions de décodage incluses.
    • Implémentation de la conversion d'une adresse virtuelle vers une adresse physique.
  • En lisant les registres de tables de pages par VMID, il devient possible d'analyser la structure de mapping mémoire GPU.

Conclusion

  • L'approche démontre la faisabilité d'un débogueur complet pour GPU AMD par accès au niveau noyau et matériel.
  • Une boucle de communication bidirectionnelle CPU-GPU est mise en place pour permettre interruption, analyse d'état et reprise pendant l'exécution.
  • Une intégration future avec RADV et Vulkan laisse entrevoir une plateforme de débogage GPU plus conviviale pour les développeurs.

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.