Analyse Nsight Compute
NVIDIA Nsight Compute (ncu) profile des kernels CUDA individuels pour déterminer
pourquoi ils sont lents et quoi optimiser. Il mesure le débit du GPU en pourcentage
du pic théorique (Speed of Light / SOL%), permettant une classification systématique
des goulots d'étranglement et une optimisation ciblée.
Quand l'utiliser
Utilisez ce skill lorsque vous rencontrez :
- Déclencheurs : L'utilisateur souhaite profiler un kernel CUDA, analyser la sortie
ncu, interpréter des rapports.ncu-repou optimiser les performances d'un kernel GPU - Symptômes : Kernel s'exécutant plus lentement que prévu, faible utilisation du GPU, besoin de classer compute-bound vs memory-bound, problèmes d'occupation
- Mots-clés : "ncu", "nsight compute", "SOL%", "speed of light", "kernel profiling", "compute-bound", "memory-bound", "latency-bound", "occupancy", "roofline", "warp stalls", "cache hit rate", "ncu-rep"
N'utilisez PAS ce skill pour :
- Le profilage au niveau système (utilisez Nsight Systems /
nsysà la place) - Le traçage d'API CUDA ou l'analyse de chronologie CPU-GPU (utilisez
nsys) - La surveillance GPU sans profilage (utilisez
nvidia-smi)
Prérequis
| Dépendance | Version | Notes |
|---|---|---|
| CUDA Toolkit | >=11.0 | Inclut ncu |
Binaire ncu | Supporté par le driver | Nsight Compute 2026.3 nécessite un driver compatible avec CUDA 13. Ou définir la variable d'env $NCU |
| GPU NVIDIA | Turing+ | Volta nécessite Nsight Compute 2025.2 ou plus ancien |
Permissions : ncu peut nécessiter sudo, CAP_SYS_ADMIN, ou --privileged
dans les conteneurs. ncu -v affiche uniquement la version ; l'absence de permission
apparaît comme ERR_NVGPUCTRPERM lorsque le premier kernel est profilé.
Principes
Intégrité des données
Il s'agit d'un système d'analyse basé sur les données. Chaque nombre présenté doit avoir une source faisant autorité. Suivez ces règles sans exception :
- Citez avant d'interpréter. Lors de la présentation de métriques issues de la sortie ncu, montrez toujours la commande ncu réelle que vous avez exécutée ET la sortie brute pertinente (lignes CSV, valeurs de métriques) avant d'énoncer une conclusion numérique.
- N'inventez jamais de métriques. Si ncu échoue, retourne une sortie inattendue, ou vous ne pouvez pas l'exécuter, dites-le explicitement. N'inventez pas de nombres plausibles. Un honnête "le profilage a échoué" est mieux que des données fabriquées.
- Attribuez chaque valeur. Pour chaque métrique que vous citez (SOL%, durée, occupation, débit), le lecteur doit pouvoir la retracer jusqu'à une ligne spécifique dans la sortie brute ncu que vous avez montrée.
Modèle mental SOL%
Speed of Light (SOL%) mesure à quel point un kernel s'approche du pic théorique du GPU :
- SOL% Compute (
Compute (SM) Throughput) = débit de l'unité SM la plus occupée en % de son pic - SOL% Mémoire (
Memory Throughput) = débit de l'unité mémoire la plus occupée (DRAM, L2, L1, mémoire partagée) en % de son pic
La métrique la plus élevée révèle généralement le type de goulot d'étranglement. Utilisez-la comme signal de classification principal. Les deux peuvent être élevés en même temps : le kernel est alors proche de la limite matérielle pour son algorithme.
Seuils de classification
| Compute % | Memory % | Goulot d'étranglement | Prochaine étape |
|---|---|---|---|
| >60 | <40 | Compute-bound | Section ComputeWorkloadAnalysis |
| <40 | >60 | Memory-bound | Section MemoryWorkloadAnalysis |
| <40 | <40 | Latency-bound | Sections LaunchStats + Occupancy |
| 40-60 | 40-60 | Équilibré | Profiler plus profondément avec les sections détaillées |
| >60 | >60 | Proche des limites matérielles | Changement algorithmique ; vérifier les deux sections de charge de travail |
Signaux supplémentaires :
- Durée <10us avec de nombreux lancements -> Limité par le surcoût de lancement (utiliser d'abord nsys)
- Les deux <40% mais occupation >50% -> Limité par les instructions (vérifier InstructionStats)
Niveaux de performance SOL%
| SOL% | Niveau | Action |
|---|---|---|
| >80% | Excellent | Ajustements mineurs uniquement |
| 60-80% | Bon | Optimisation ciblée |
| 40-60% | Correct | Optimisation significative nécessaire |
| <40% | Médiocre | Refonte majeure nécessaire |
Profilage par section
Utilisez toujours des drapeaux --section ciblés au lieu de la collecte en bloc --set.
Les sections individuelles sont plus rapides et plus chirurgicales. Ne passez à --set basic ou
--set detailed que lorsqu'une exploration large est nécessaire.
ncu vs nsys
| Outil | Portée | Surcharge | Objectif |
|---|---|---|---|
| nsys | Au niveau système | 5-10% | Trouver quels kernels optimiser |
| ncu | Au niveau kernel | 10-100x plus lent | Comprendre pourquoi un kernel est lent |
Utilisez d'abord nsys pour identifier les principaux kernels en temps GPU, puis ncu pour une analyse approfondie de ces kernels spécifiques.
Workflow
Choisissez votre chemin en fonction de la demande :
- Requête de connaissance (quelles métriques utiliser, --section vs --set, comment filtrer les kernels) : Répondez directement à partir des Principes, de la Référence des commandes et des Références ci-dessous. N'exécutez PAS ncu.
- Diagnostic rapide (classer le goulot d'étranglement, vérifier SOL%) : Étape 1 uniquement. Approfondissez si l'utilisateur le souhaite.
- Diagnostic spécifique (conflits de banques, pression de registres, occupation) : Vérification rapide SOL% (Étape 1), puis allez directement à la section pertinente à l'Étape 2.
- Analyse approfondie (rapport détaillé, recommandations d'optimisation) : Étapes complètes 1 à 5. Présentez le rapport structuré complet avec toutes les métriques clés (SOL%, durée, occupation) dans votre réponse finale — ne répartissez pas le rapport sur plusieurs messages et ne le remplacez pas par un bref résumé.
Étape 0 : Vérifier ncu
ncu -v
# Ou : $NCU -v
S'il n'est pas trouvé, assurez-vous que le toolkit CUDA est installé ou définissez la variable d'env NCU sur le chemin du binaire.
Étape 1 : Diagnostic SOL%
Commencez toujours par SpeedOfLight pour classer le goulot d'étranglement :
ncu --section SpeedOfLight --csv \
--kernel-name regex:"KERNEL" \
--launch-skip 5 --launch-count 3 \
-- COMMAND
Lisez Compute (SM) Throughput et Memory Throughput dans la sortie. Classez en utilisant les seuils ci-dessus.
Étape 2 : Approfondir avec des sections ciblées
En fonction de la classification de l'Étape 1, ajoutez des sections :
| Classification | Sections à ajouter |
|---|---|
| Compute-bound | ComputeWorkloadAnalysis |
| Memory-bound | MemoryWorkloadAnalysis |
| Latency-bound | LaunchStats, Occupancy |
| Warp stalls | WarpStateStats, SchedulerStats |
| Détail d'instructions nécessaire | InstructionStats |
Incluez toujours LaunchStats et Occupancy lors du diagnostic des kernels latency-bound.
Ceux-ci révèlent la pression de registres, les limites de mémoire partagée et les problèmes de taille de bloc.
Exemple -- plongée approfondie memory-bound :
ncu --section SpeedOfLight --section MemoryWorkloadAnalysis --csv \
--kernel-name regex:"embedding_lookup" \
--launch-count 3 \
-- python script.py
Exemple -- plongée approfondie compute-bound :
ncu --section SpeedOfLight --section ComputeWorkloadAnalysis --csv \
--kernel-name regex:"gemm|nvjet" \
--launch-count 3 -- python script.py
Exemple -- enquête sur l'occupation :
ncu --section SpeedOfLight --section LaunchStats --section Occupancy --csv \
--kernel-name regex:"small_kernel" \
-- python script.py
Étape 3 : Analyse Roofline (Optionnelle)
Pour une compréhension visuelle de l'équilibre compute vs mémoire. Les sections roofline
sont des graphiques : sur le CLI, ils s'impriment uniquement avec --print-details all, ce qui
liste les nombres derrière le graphique (travail et trafic atteints et pics). Pour voir le
graphique, enregistrez un rapport avec -o et ouvrez-le dans l'interface Nsight Compute.
ncu --section SpeedOfLight_RooflineChart --print-details all \
--kernel-name regex:"KERNEL" -- COMMAND
Pour un roofline hiérarchique spécifique à la précision :
# Kernels FP16
ncu --section SpeedOfLight_HierarchicalHalfRooflineChart --print-details all \
--kernel-name regex:"KERNEL" -- COMMAND
# Kernels Tensor core
ncu --section SpeedOfLight_HierarchicalTensorRooflineChart --print-details all \
--kernel-name regex:"KERNEL" -- COMMAND
Interprétation : un kernel à gauche du point de crête = memory-bound ; à droite = compute-bound ;
loin sous les deux toits = problème de latence/occupation. Voir references/roofline-analysis.md.
Étape 4 : Interpréter et Optimiser
- Identifiez le goulot d'étranglement dominant à partir de la classification SOL%
- Consultez l'analyse détaillée et les stratégies d'optimisation dans
references/bottleneck-guide.md - Appliquez d'abord l'optimisation au plus fort impact
- Re-profilez pour valider l'amélioration et détecter les changements de goulot d'étranglement
Étape 5 : Valider
Re-profilez le même kernel après optimisation :
ncu --section SpeedOfLight --csv \
--kernel-name regex:"optimized_kernel" \
--launch-count 3 \
-- python optimized_script.py
Comparez : Le pourcentage de débit a-t-il augmenté ? La durée a-t-elle diminué ? Le type de goulot d'étranglement a-t-il changé ?
Profilage de Kernels Compilés JIT (Triton/cuTile/CuTeDSL)
Les kernels compilés JIT déclenchent un auto-réglage lors du premier appel. Isolez l'exécution réelle :
- Échauffez d'abord : Exécutez le kernel 3 à 5 fois pour terminer la compilation JIT et l'auto-réglage, puis
torch.cuda.synchronize(). - Utilisez des marqueurs de profileur : Encadrez la région mesurée avec
cudaProfilerStart()/cudaProfilerStop(). - Utilisez
--profile-from-start offpour que ncu ne capture que la région marquée :
# Échauffement (JIT + auto-réglage)
for _ in range(5):
result = kernel(inputs)
torch.cuda.synchronize()
# Profilage de l'état d'équilibre uniquement
torch.cuda.cudart().cudaProfilerStart()
for _ in range(3):
result = kernel(inputs)
torch.cuda.synchronize()
torch.cuda.cudart().cudaProfilerStop()
ncu --profile-from-start off --section SpeedOfLight --csv \
--kernel-name regex:"target_kernel" \
--launch-count 3 -- python script.py
Alternative : utilisez --launch-skip N pour sauter les lancements d'auto-réglage. Voir
references/advanced-profiling.md pour les alternatives avec plage NVTX et mode de rejeu.
Analyse Programmatique des Rapports
Extrayez des métriques à partir de fichiers .ncu-rep ou .ncu-repz en utilisant le module Python ncu_report
(dans extras/python/ de l'installation de Nsight Compute) :
import ncu_report
ctx = ncu_report.load_report("report.ncu-rep")
for rng in ctx:
for action in rng:
name = action.name()
# SpeedOfLight : "Compute (SM) Throughput" et "Memory Throughput"
compute = action["sm__throughput.avg.pct_of_peak_sustained_elapsed"].as_double()
memory = action["gpu__compute_memory_throughput.avg.pct_of_peak_sustained_elapsed"].as_double()
duration = action["gpu__time_duration.sum"].as_uint64()
if compute > 60:
classification = "compute-bound"
elif memory > 60:
classification = "memory-bound"
else:
classification = "latency-bound"
print(f"{name}: {classification} (compute={compute:.1f}%, mem={memory:.1f}%, {duration}ns)")
Voir references/python-report-api.md pour l'API complète (classes IContext, IRange, IAction, IMetric).
Formats de sortie
Sortie CSV (pour les scripts et l'analyse automatisée) :
ncu --csv --section SpeedOfLight --kernel-name regex:"KERNEL" -- COMMAND
ncu --csv --page raw --section SpeedOfLight -- COMMAND # Toutes les métriques à plat
Le CSV par défaut a une ligne par métrique. Ses colonnes incluent ID (le
lancement profilé), Kernel Name, Section Name, Metric Name, Metric Unit
et Metric Value ; les résultats de règle sont des lignes qui remplissent Rule Name,
Rule Description et Estimated Speedup. Un Metric Name peut se répéter
entre les sections (Memory Throughput est % dans SpeedOfLight et byte/s dans
MemoryWorkloadAnalysis), donc filtrez aussi sur Section Name. --page raw donne une
ligne par lancement, une colonne par métrique, et une deuxième ligne d'unités. Les valeurs sont en
unités de base (ns, hz, %).
Pendant le profilage, les lignes ==PROF== de ncu et la sortie propre de l'application partagent
stdout avec le CSV. Pour un CSV propre, écrivez un rapport et relisez-le :
Fichiers de rapport (pour analyse ultérieure) :
ncu -o report.ncu-rep --section SpeedOfLight -- COMMAND
ncu --import report.ncu-rep --csv # Une ligne par métrique
ncu --import report.ncu-rep --csv --page raw # Une ligne par lancement
Donnez à -o l'extension : sans extension, Nsight Compute 2026.3 et plus récent écrivent le
report.ncu-repz compressé en zstd, et les versions plus anciennes écrivent report.ncu-rep.
--import et ncu_report lisent les deux.
Lignes de métriques clés (valeurs Metric Name) :
| Metric Name | Section | Signification |
|---|---|---|
Duration | SpeedOfLight | Temps d'exécution |
Compute (SM) Throughput | SpeedOfLight | % du pic de calcul |
Memory Throughput | SpeedOfLight | % du pic de l'unité mémoire la plus occupée |
SM Frequency | SpeedOfLight | Horloge à laquelle le profil a été exécuté |
Achieved Occupancy | Occupancy | Warps actifs / warps max (%) |
Indicateurs de succès :
- Valeurs SOL% présentes dans la sortie -> profilage réussi
- Valeurs de durée raisonnables (pas 0 ou extrêmement grandes)
- Plusieurs lancements capturés lorsque
--launch-count > 1
Exemples
Exemple : Classer un Kernel GEMM
Les kernels cuBLAS GEMM sur Blackwell sont nommés nvjet_*, donc faites correspondre les deux noms :
ncu --section SpeedOfLight --csv \
--kernel-name regex:"gemm|nvjet" \
--launch-skip 5 --launch-count 3 \
-- python train.py
Sortie pour un matmul FP16 4096x4096 sur B200 (colonnes et lignes abrégées) :
"ID",...,"Kernel Name",...,"Section Name","Metric Name","Metric Unit","Metric Value",...
"0",...,"nvjet_sm100_hsh_128x256_64x6_2x2f_2cta_h_bz_NNT",...,"GPU Speed Of Light Throughput","Memory Throughput","%","38.38",
"0",...,"nvjet_sm100_hsh_128x256_64x6_2x2f_2cta_h_bz_NNT",...,"GPU Speed Of Light Throughput","Duration","ns","97600",
"0",...,"nvjet_sm100_hsh_128x256_64x6_2x2f_2cta_h_bz_NNT",...,"GPU Speed Of Light Throughput","Compute (SM) Throughput","%","77.11",
Interprétation : compute-bound (77.1% compute, 38.4% mémoire). Prochaine étape :
vérifier l'utilisation du tensor core avec --section ComputeWorkloadAnalysis.
Exemple : Diagnostiquer un Kernel d'Embedding Memory-Bound
PyTorch embedding lookup exécute vectorized_gather_kernel, donc faites-le correspondre aussi :
ncu --section SpeedOfLight --section MemoryWorkloadAnalysis --csv \
--kernel-name regex:"gather|index|embedding" \
--launch-count 3 -- python train.py
Vérifiez les taux de succès du cache L1/L2 dans la sortie : des taux faibles suggèrent une bande passante mémoire DRAM élevée. Voir references/bottleneck-guide.md pour les stratégies.