Loading...
Loading...
NCU-driven iterative optimization workflow for CUDA/CUTLASS/Triton/CuTe DSL kernels. MANDATORY: every optimization MUST start with NCU profiling, followed by multi-dimensional analysis, then targeted code modification, then re-profiling to verify. Supports roofline, memory hierarchy, warp stalls, instruction mix, occupancy, divergence analysis. Provides implementation-specific code modifications: Native CUDA (launch config, memory patterns, async copy, Tensor Core), CUTLASS (ThreadblockShape, stages, epilogue, schedule policy, alignment), Triton (autotune params, compiler hints, tl.* API patterns), CuTe DSL (threads_per_cta, elems_per_thread, tiled_copy, copy atom, shared memory, warp/cta reduce). Use when optimizing any CUDA kernel performance.
npx skill4agent add bruce-lee-ly/cuda_auto_tune cuda-auto-tuneSTOP — Do you have NCU profile data for this kernel?
NO → Go to Step 1. Do NOT touch any kernel code.
YES → Go to Step 2.--diff┌─────────────────────────────────────────────────────────────────────┐
│ Step 1: Profile (NCU --set full) │
│ ↓ │
│ Step 2: Multi-dimensional analysis + identify kernel type │
│ ↓ │
│ Step 3: Apply type-specific playbook (one change per iteration) │
│ ↓ │
│ Step 4: Re-profile + diff → improved? → loop or stop │
│ ↑ │ │
│ └───────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘# Native CUDA / CUTLASS binaries
bash cuda-auto-tune/scripts/ncu_profile.sh ./kernel report_v1
# Triton / Python
bash cuda-auto-tune/scripts/ncu_profile.sh "python your_kernel.py" report_v1
# CuTe DSL / Python
bash cuda-auto-tune/scripts/ncu_profile.sh "python your_cutedsl_kernel.py" report_v1--set fullncu --set full -o report_v1 --target-processes all ./your_kernel
ncu --import report_v1.ncu-rep --page raw --csv > report_v1.csv
python3 cuda-auto-tune/scripts/ncu_analyse.py report_v1.csv# CUTLASS only
ncu --set full -o report_v1 --target-processes all \
--kernel-name "cutlass_\|sm90_\|ampere_" ./cutlass_program
# Triton only
ncu --set full -o report_v1 --target-processes all \
--kernel-name "triton_" "python triton_kernel.py"
# CuTe DSL (kernel name often generic — use --type override in analysis)
python3 cuda-auto-tune/scripts/ncu_analyse.py report_v1.csv --type cutedslncu_reports/
├── report_v1.ncu-rep # Full binary report
├── report_v1.csv # Raw metrics CSV
├── report_v1_analysis.md # Deep analysis report
└── report_v1_summary.txt # Per-kernel summary| Type | Detection signals |
|---|---|
| Native CUDA | No library prefix; hand-written |
| CUTLASS | |
| Triton | |
| CuTe DSL | Generic names from |
| Library | |
| Dimension | Key NCU metrics | Output |
|---|---|---|
| Roofline | SM throughput, memory throughput | compute-bound / memory-bound / latency-bound / balanced |
| Memory hierarchy | L1/L2 hit rate, coalescing ratio, DRAM throughput | cache efficiency + bandwidth sub-bottleneck (DRAM/L2/L1) |
| Warp stalls | PC sampling stall reasons (long_scoreboard, wait, barrier, ...) | top stall reasons with percentages |
| Instruction mix | pipe FMA/ALU/LSU/Tensor utilization | pipeline imbalance, Tensor Core usage |
| Occupancy | active warps %, limiter breakdown (register/smem/warp/block) | limiting factor + register count + smem size |
| Memory hazards | bank conflicts, register spills (local store sectors) | severity and root cause |
| Divergence | avg threads executed vs avg threads active (true) | divergence percentage |
| Type | Key focus areas |
|---|---|
| Native CUDA | launch config (block size, grid), memory access patterns, async copy (cp.async/TMA), Tensor Core opportunity |
| CUTLASS | ThreadblockShape, WarpShape, stages, alignment, schedule policy, epilogue fusion, CTA swizzle |
| Triton | |
| CuTe DSL | |
SM% > MEM% + 20 → COMPUTE_BOUND
MEM% > SM% + 20 → MEMORY_BOUND
├─ DRAM throughput > 70% → DRAM-Bound (near HBM ceiling)
├─ L2 hit < 50%, DRAM > 40% → DRAM-Bound (L2 miss driven)
├─ L1 hit < 20%, L2 hit >= 50% → L2-Bound
└─ L1 hit < 20% → L1-Bound
SM% < 40 AND MEM% < 40 → LATENCY_BOUND
SM% > 60 AND MEM% > 60 → BALANCED (near peak)=== Conclusion ===
Kernel: {kernel_name}
Type: {Native CUDA | CUTLASS | Triton | CuTe DSL}
Arch: SM_{arch}
Overall: {COMPUTE_BOUND | MEMORY_BOUND | LATENCY_BOUND | BALANCED}
Duration: {duration_us} us
Roofline: SM {sm}%, MEM {mem}%, DRAM {dram}%
Occupancy: {occ}% (theoretical: {theo}%), limited by {limiter}
Regs/Thread: {regs}, Smem/Block: {smem} KB
Findings (sorted by severity):
[CRITICAL] {finding}: {NCU evidence with numbers} -> {specific action}
[WARNING] {finding}: {NCU evidence with numbers} -> {specific action}
[INFO] {finding}: {NCU evidence with numbers}
Optimization priorities:
1. {highest_priority} (expected gain: Nx, evidence: {metric}={value})
2. {second_priority} (expected gain: Nx, evidence: {metric}={value})
3. {third_priority} (expected gain: Nx, evidence: {metric}={value})| NCU finding | Action | Code pattern |
|---|---|---|
| Occupancy < 50%, block size < 128 | Increase block size to 128–256 | |
| Registers are occupancy limiter | Cap registers via | |
| Grid too small (< SM count) | Ensure enough blocks for full SM coverage | |
| Occupancy low, blocks limiter | Reduce block size to fit more blocks per SM | Try 128 instead of 256 |
| NCU finding | Action | Code pattern |
|---|---|---|
| Load coalescing ratio > 8 | Ensure warp-contiguous addressing, AoS→SoA | |
| Store coalescing ratio > 8 | Use shared memory staging for scatter writes | Write to smem first, then coalesced writeback |
| L1 hit rate < 20% | Use | Tile into shared memory with |
| L2 hit rate < 50% | Use L2 persistence hints (Ampere+) | |
| DRAM throughput > 80% | Reduce data movement: mixed precision, compression | |
| Bank conflicts > 100K | Pad shared memory or swizzle layout | |
| Register spills > 0 | Reduce per-thread state, use | Simplify accumulators, split into sub-kernels |
| NCU finding | Action | Code pattern |
|---|---|---|
| stall_long_scoreboard > 30% (SM>=80) | Use | |
| stall_long_scoreboard > 30% (SM>=90) | Use TMA for bulk async transfers | |
| stall_barrier > 25% | Reduce sync frequency, use warp primitives | |
| stall_wait > 30%, long_scoreboard < 15% | Pipeline over-buffered, reduce depth | Remove one buffer stage |
| stall_math_pipe_throttle > 20% | Compute saturated (positive signal) | Consider Tensor Core or reduce FLOPs |
| NCU finding | Action |
|---|---|
| pipe_tensor < 5%, FP16/BF16 workload with GEMM-like pattern | Use WMMA ( |
| pipe_tensor < 5%, but data is FP32 | Use TF32 path via |
| pipe_fma_fp16 > 10%, pipe_tensor < 5% | Switch from scalar FP16 FMA to Tensor Core path |
// NCU evidence: coalescing ratio > 4 for 32-bit loads
// Before: scalar loads
float val = input[idx];
// After: vectorized 128-bit load (4x float)
float4 val = reinterpret_cast<const float4*>(input)[idx / 4];sm80_sm90_ampere_hopper_tensoropsimt128x128x32256x128x64x3x5align8WarpSpecializedWarpSpecializedCooperativeWarpSpecializedPingpong| NCU finding | Action |
|---|---|
| Occupancy < 40%, smem is limiter | Reduce ThreadblockShape (e.g., 256x128→128x128) or reduce stages |
| Occupancy < 40%, registers are limiter | Use smaller WarpShape (e.g., 64x64→32x32) to reduce per-thread regs |
| SM throughput < 30%, grid is small | Increase ThreadblockShape to process more elements per CTA |
| SM throughput > 80%, MEM < 40% | Already compute-bound; increase pipeline stages for more overlap |
| NCU finding | Action |
|---|---|
| stall_long_scoreboard > 30% | Increase stages (Ampere: 3→5, Hopper: 2→3) |
| stall_wait > 30%, long_scoreboard < 15% | Pipeline over-buffered; reduce stages to save smem |
| Smem limiter + stages > 3 | Reduce stages to free smem for higher occupancy |
| NCU finding | Action |
|---|---|
| Load coalescing > 4, alignment < 8 | Increase CUTLASS alignment to 8 (128 bytes); pad matrix leading dims to multiples of alignment |
| SIMT path used but data supports TensorOp | Switch to |
| TensorOp configured but pipe_tensor < 5% | Check alignment requirements — LD must be multiple of InstructionShape::kK |
| NCU finding | Action |
|---|---|
| CUTLASS 2.x on SM>=90 | Upgrade to CUTLASS 3.x with WarpSpecialized + TMA (1.2–1.5x gain) |
| L2 hit rate < 50% on large GEMM | Add ThreadblockSwizzle (2.x: |
| stall_long_scoreboard > 30% on Hopper | Switch to |
| NCU finding | Action |
|---|---|
| Multiple CUTLASS kernels back-to-back (e.g., GEMM + bias + activation) | Fuse into single kernel via CUTLASS epilogue visitor tree |
| High DRAM traffic (read+write GB > expected) | Move post-GEMM ops into epilogue to eliminate intermediate tensors |
triton_poi_triton_red_triton_per_@triton.jittorch._inductor.config@triton.jit| NCU finding | Action |
|---|---|
| Registers >= 128, num_warps >= 8 | CRITICAL: reduce num_warps (try 4 or 2) |
| Registers >= 64, num_warps >= 8 | Reduce num_warps to 4 |
| Occupancy < 40%, register-limited | Reduce num_warps AND/OR reduce BLOCK_* tile sizes |
| SM throughput < 30%, few warps | Increase num_warps to improve latency hiding |
| NCU finding | Action |
|---|---|
| stall_long_scoreboard > 30% | Increase num_stages (2→3→4 on Ampere, 2→3 on Hopper) |
| stall_wait > 30%, long_scoreboard < 15% | Decrease num_stages (over-buffered) or increase tile work |
| Smem is occupancy limiter | Decrease num_stages (each stage doubles smem buffer) |
| On Hopper + long_scoreboard high | Also consider |
| NCU finding | Action |
|---|---|
| Register pressure high | Reduce BLOCK_M, BLOCK_N, or BLOCK_K |
| SM throughput low, compute-bound opportunity | Increase BLOCK_M/BLOCK_N for more compute per tile |
| DRAM bandwidth near ceiling | Increase BLOCK_K for more data reuse before writeback |
| NCU finding | Action | Code pattern |
|---|---|---|
| Load coalescing > 8 | Add stride hints | |
| Uncoalesced on transposed input | Use structured pointers | |
| L1 hit rate low | Verify access pattern continuity | Ensure innermost dim stride == 1 |
| NCU finding | Action |
|---|---|
pipe_tensor < 5%, kernel uses | 1) |
pipe_tensor < 5%, no | GEMM-like pattern missing — restructure to use |
@triton.autotune(
configs=[
triton.Config({'BLOCK_M': 128, 'BLOCK_N': 128, 'BLOCK_K': 32}, num_warps=4, num_stages=3),
triton.Config({'BLOCK_M': 64, 'BLOCK_N': 64, 'BLOCK_K': 64}, num_warps=4, num_stages=4),
triton.Config({'BLOCK_M': 128, 'BLOCK_N': 64, 'BLOCK_K': 32}, num_warps=8, num_stages=3),
],
key=['M', 'N', 'K'],
)
@triton.jit
def kernel(...):
...| Parameter | Effect | Typical range |
|---|---|---|
| Warps per CTA; affects occupancy, barrier cost, reduce cost | 128–512 |
| Elements per thread; affects register pressure, data reuse | 4–32 |
| CopyAtom width; affects vectorized load/store bandwidth | 32, 64, 128 |
| Smem staging buffer | Pipeline depth × tile size; affects smem footprint | Minimize for occupancy |
| NCU finding | Action |
|---|---|
| Occupancy < 40%, registers are limiter | Reduce |
| Occupancy < 40%, smem is limiter | Reduce |
| Registers >= 128, warps >= 8 | CRITICAL: reduce |
| NCU finding | Action |
|---|---|
| Load coalescing > 8 | 1) Increase |
| stall_long_scoreboard > 30% | 1) Increase |
| stall_wait > 30%, long_scoreboard < 15% | Pipeline over-buffered; increase |
| NCU finding | Action |
|---|---|
| stall_barrier > 25% | 1) Reduce |
| High barrier + small reduction | Use warp-only reduce without smem for small element counts |
| Multiple sync_threads per iteration | Minimize sync points; use async pipeline commit/wait patterns |
| NCU finding | Action |
|---|---|
| Divergence > 20% | Adjust |
| Predicated copies show high divergence | Ensure N is divisible by |
| NCU finding | Action |
|---|---|
| pipe_tensor < 5%, FP16 GEMM-like ops | Use |
| pipe_fma high but pipe_tensor low (non-GEMM ops like RMSNorm/LayerNorm) | Tensor Core not applicable for reductions — focus on memory and barrier optimization instead |
# Clear compilation cache to ensure re-compilation
rm -rf __pycache__/ .cache/ /tmp/cutlass_cute_cache/
# Then re-profile
bash cuda-auto-tune/scripts/ncu_profile.sh "python your_cutedsl_kernel.py" report_v2# Clear JIT caches first
rm -rf ~/.triton/cache # Triton
rm -rf __pycache__/ .cache/ # CuTe DSL
# Profile updated version
bash cuda-auto-tune/scripts/ncu_profile.sh ./kernel_v2 report_v2
# or
bash cuda-auto-tune/scripts/ncu_profile.sh "python kernel_v2.py" report_v2python3 cuda-auto-tune/scripts/ncu_analyse.py ncu_reports/report_v2.csv --diff ncu_reports/report_v1.csv| Check | Criteria |
|---|---|
| Duration improved? | |
| Target bottleneck improved? | The specific metric that triggered the change improved |
| No new bottlenecks? | No new CRITICAL findings in the diff report |
| At hardware ceiling? | SM throughput > 80% or DRAM throughput > 85% means near peak |
=== Iteration {N} ===
Change: {what was changed and why}
NCU evidence: {metric}={before_value} -> {finding}
Report: report_v{N}.csv
Result:
Duration: {before} us -> {after} us ({delta}%)
Target metric: {metric}={before} -> {after}
New findings: {any new issues introduced}
Decision: {CONTINUE to next bottleneck | STOP — at ceiling | ROLLBACK — regression}| Metric | NCU key |
|---|---|
| Duration | |
| SM throughput | |
| Memory throughput | |
| DRAM throughput | |
| L1 hit rate | |
| L2 hit rate | |
| Load coalescing | |
| Bank conflicts | |
| Register spills | |
| Occupancy | |
| Warp eligibility | |
| Registers/thread | |
| Smem/block | |