> Analyze host/CPU overhead in TensorRT-LLM inference from nsys traces. Detect whether host overhead is the bottleneck using GPU idle ratio, host prep exposed ratio, and per-phase evidence. For regressions, isolate forward steps via allreduce/NVTX patterns, compare host operation breakdowns across versions, and identify scheduling or request-management overhead. Supports optional inter-kernel gap, eager-vs-graph, pattern mapping, and multi-rank straggler inter-step gap, scheduling overhead, forward step isolation, nsys iteration analysis, NVTX breakdown, request management overhead, GPU idle, host bottleneck, host prep exposed, inter-kernel gap, bubble analysis, graph coverage, eager kernel, rank imbalance, straggler detection.
npx skills add https://github.com/NVIDIA/TensorRT-LLM --skill perf-host-analysis
Analyze host/CPU overhead in TensorRT-LLM inference workloads from nsys traces. This skill operates in two phases:
| Phase | Question | Input | Output |
|-------|----------|-------|--------|
| Detection | Is host overhead the bottleneck? | Single nsys trace | YES/NO verdict with metric evidence |
| Root Cause | What specifically regressed? | One or two nsys traces | NVTX per-step breakdown, regression sources, optional kernel-level drill-down |
perf-analysis for bottleneck classification (Detection)Do NOT use when:
perf-nsight-compute-analysis)workload-instrumentation first).sqlite or .nsys-rep) from a TRT-LLM benchmark runIn an LLM inference loop, each iteration consists of:
[inter-step gap] -> [_forward_step] -> [inter-step gap] -> [_forward_step] -> ...
The forward step includes GPU kernel execution (GEMM, attention, normalization, allreduce) plus host-side preparation. The inter-step gap includes host-side work between forward steps (scheduling, request fetching, broadcasting, sampling, response handling).
See references/trtllm-nvtx-ranges.md for the full per-operation breakdown and timing ranges.
Host overhead only hurts performance when it is exposed -- the GPU is idle waiting for work. When host prep overlaps with GPU execution, it is hidden and free. See references/metrics.md (M3 section) for diagrams and the exposed/hidden computation.
In TP configurations, forward steps are isolated via allreduce kernel grouping (deterministic count per transformer layer). For TP=1, NVTX _forward_step ranges are used directly. See references/iteration-isolation-techniques.md for the full algorithm.
Iterations are classified by NVTX marker text into context (eager, no CUDA graphs) and generation (CUDA graph replay). Per-phase analysis is critical because aggregate metrics can mask phase-specific bottlenecks. See references/phase-classification.md.
Determine whether host overhead is the primary bottleneck.
Six metrics in four categories. See references/metrics.md for full definitions, formulas, and SQL queries.
| # | Metric | Threshold | What it answers |
|---|--------|-----------|-----------------|
| M1 | GPU idle ratio | > 0.30 | Is the GPU starved for work? |
| M2 | Launch overhead ratio | > 0.10 | Is kernel launch itself expensive? |
| M3a | Host prep exposed ratio | > 0.50 | How well is host prep pipelined? |
| M3b | Host prep perf impact | > 0.05 | How much throughput does exposed prep cost? |
| M3c | Host prep idle attribution | > 0.50 | Is host prep the main cause of GPU idle? |
| M4 | GPU utilization | < 0.60 | Is GPU utilization too low? |
| M5 | NCCL ratio (caveat) | > 0.20 | Is communication a confounding factor? |
Host prep confirmation rule: Host prep is a confirmed bottleneck only when both M3b AND M3c cross their thresholds.
Thresholds are configurable with per-phase variants. See references/thresholds.md.
# Accept .sqlite or .nsys-rep
ls -la <trace_file>
# If .nsys-rep, export to SQLite first
nsys export -t sqlite -o <output.sqlite> <input.nsys-rep>
python scripts/detect_host_overhead.py \
--trace /path/to/trace.sqlite \
--output /path/to/verdict.json
The script computes M1, M2, M4, M5 from SQL, optionally M3 via range intersection, applies the verdict logic, and outputs structured JSON. See references/output-format.md for the output schema.
For manual metric extraction via SQL, see references/nsys-schema.md.
Overall Verdict:
if aggregate_verdict == YES or context_verdict == YES or generation_verdict == YES:
overall_verdict = YES
Per-phase analysis can elevate the verdict but never demote it.
Format using the template in references/output-format.md.
Next Steps:
perf-host-optimization skillperf-nsight-compute-analysis for kernel SOL% or trace-interpretation for full classificationIdentify which specific host operations regressed and by how much. Works with a single trace (breakdown) or two traces (comparison).
Profile both versions (if comparing) with identical settings:
nsys profile -o /path/to/trace \
-t cuda,nvtx,osrt \
--force-overwrite=true \
--cuda-memory-usage=true \
-w true \
<benchmark_command> --num_requests 500
nsys export --type=sqlite --force-overwrite=true -o trace.sqlite trace.nsys-rep
# Two-trace comparison
python scripts/analyze_host_overhead.py \
--baseline /path/to/baseline/trace.sqlite \
--target /path/to/target/trace.sqlite \
--baseline-label "v1.1" \
--target-label "main" \
--output /path/to/output/analysis.txt
# Single-trace breakdown
python scripts/analyze_host_overhead.py \
--baseline /path/to/trace.sqlite \
--baseline-label "current"
The script produces:
Per-Step Wall Time:
Avg wall time per step: 3,317 us (baseline) vs 3,978 us (target) +19.9%
This is the primary regression metric.
NVTX Breakdown:
Operation | baseline (us/step) | target (us/step) | Delta | Status
_fetch_new_requests | 36 | 270 | +234 | REGRESSION
broadcast_requests | - | 250 | +250 | NEW
_update_requests | 413 | 723 | +310 | REGRESSION
Focus on operations with large absolute deltas.
GPU Kernel Comparison:
Kernels per step (launched): 6.2 (baseline) vs 21.9 (target) +253%
More individual launches = more host-side launch overhead.
When the NVTX breakdown identifies a regressing operation but does not reveal *why* (the overhead is inside the GPU dispatch, not between NVTX ranges), drill below NVTX operations into individual GPU kernel launches.
See references/kernel-level-analysis.md for full technique details, SQL queries, and examples.
When to drill down:
| Technique | Question | Key Output |
|-----------|----------|------------|
| Inter-Kernel Gap Analysis | Where is the GPU idle between kernels? | Gap bucket distribution, top-N largest gaps with source mapping |
| Eager vs Graph Classification | What fraction of kernels are graph-captured? | Graph coverage ratio, list of eager kernels with source attribution |
| Repeating-Pattern Mapping | Which functional group within a layer has the most overhead? | Per-group gap totals, priority ranking |
| Straggler Detection | Is one rank consistently slower? | Straggler rank ID, root cause (extra host work, queue depth feedback loop) |
| Finding | Optimization Pattern |
|---------|---------------------|
| Large gaps from Python tensor view chains | CUSTOM_OP — replace with C++ custom op |
| Graph-capturable kernels running eagerly | GRAPH_EXPAND — fix partition poisoning |
| Monolithic custom op blocking graph capture | GRAPH_SPLIT — split into capturable + eager parts |
| Host-device sync (.item()) in per-layer code | SYNC (Pattern 1: pre-compute on CPU) + HOIST (Variant B: pass from step level) |
| Per-layer buffer allocation | ALLOC — pre-allocate at init |
| Straggler rank with extra host work | Apply targeted optimization to coordinator-only code paths |
Symptom: _fetch_new_requests regressed 5-10x, new broadcast_requests operation.
Cause: Request fetching refactored for multi-rank broadcasting in TP.
Mitigation: Optimize broadcast path; batch request state updates.
Symptom: 3-5x more cudaLaunchKernel calls per step, similar GPU time.
Cause: Operations that were fused or graph-captured are now individual launches.
Mitigation: Re-fuse kernels; extend CUDA graph capture scope.
Symptom: New NVTX ranges like _write_finish_reasons, handle_additional_outputs.
Cause: New features added to the inference loop without overhead budgeting.
Mitigation: Defer non-critical bookkeeping to async paths; batch updates.
Symptom: Massive elementwise/reduce kernel counts in "steady state" analysis.
Cause: Analysis window includes flashinfer JIT compilation phase.
Fix: Use allreduce-based iteration isolation, not kernel density or time windows.
Symptom: Aggregate metrics below threshold, but context iterations have 50% GPU idle.
Cause: Generation iterations dilute the context-phase bottleneck.
Fix: Per-phase analysis in Detection phase catches this.
In CUPTI_ACTIVITY_KIND_KERNEL, shortName is an integer referencing StringIds.id. Always join. See references/nsys-schema.md.
Most NVTX events have textId (integer) but NULL text. Join with StringIds. See references/nsys-schema.md.
In TP configurations, each rank reports NVTX ranges independently. De-duplicate by grouping entries within 100us of each other.
When TP ranks report overlapping NVTX ranges, gap = next_start - prev_end can be negative. Use the maximum end time when de-duplicating.
The allreduce-based window captures context+generation phases; steady-state NVTX filtering captures generation-only. Both are valid; use the appropriate one for your comparison goal.
When analysis is complete and the verdict is YES, hand off to the perf-host-optimization skill with:
| File | Contents |
|------|----------|
| references/metrics.md | Full metric definitions, formulas, SQL queries, M3 sub-metric analysis |
| references/thresholds.md | Aggregate and per-phase threshold tables |
| references/phase-classification.md | NVTX marker parsing, iteration classification, per-phase aggregation |
| references/output-format.md | Report template and integration JSON schema |
| references/examples.md | Worked scenarios (aggregate, phase-specific, and case study) |
| references/iteration-isolation-techniques.md | Allreduce, NVTX, and kernel-density iteration isolation techniques |
| references/trtllm-nvtx-ranges.md | TRT-LLM NVTX range reference with per-operation timings |
| references/kernel-level-analysis.md | Kernel-level drill-down techniques: gap analysis, graph classification, pattern mapping, straggler detection |
| references/nsys-schema.md | nsys SQLite schema reference and useful queries |
| scripts/analyze_host_overhead.py | Python script for Phase 2 root cause analysis |
| scripts/detect_host_overhead.py | Python script for Phase 1 detection verdict |
Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.
Access NCBI GEO for gene expression/genomics data. Search/download microarray and RNA-seq datasets (GSE, GSM, GPL), retrieve SOFT/Matrix files, for transcriptomics and expression analysis.
Bayesian modeling with PyMC. Build hierarchical models, MCMC (NUTS), variational inference, LOO/WAIC comparison, posterior checks, for probabilistic programming and inference.
Multi-objective optimization framework. NSGA-II, NSGA-III, MOEA/D, Pareto fronts, constraint handling, benchmarks (ZDT, DTLZ), for engineering design and optimization problems.
Statistical modeling toolkit. OLS, GLM, logistic, ARIMA, time series, hypothesis tests, diagnostics, AIC/BIC, for rigorous statistical inference and econometric analysis.
Add unsigned integer (uint) type support to PyTorch operators by updating AT_DISPATCH macros. Use when adding support for uint16, uint32, uint64 types to operators, kernels, or when user mentions enabling unsigned types, barebones unsigned types, or uint support.
Convert PyTorch AT_DISPATCH macros to AT_DISPATCH_V2 format in ATen C++ code. Use when porting AT_DISPATCH_ALL_TYPES_AND*, AT_DISPATCH_FLOATING_TYPES*, or other dispatch macros to the new v2 API. For ATen kernel files, CUDA kernels, and native operator implementations.
Write docstrings for PyTorch functions and methods following PyTorch conventions. Use when writing or updating docstrings in PyTorch code.
Take nvidia/perf-host-analysis from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.