CuTe DSL
CuTe DSL is a Python-based domain-specific language for GPU kernel development,
part of CUTLASS 4.x. It provides Python abstractions over CUTLASS C++ templates
with JIT compilation to optimized CUDA kernels via MLIR and ptxas.
When to Use
Triggers:
- Writing CUDA kernels in Python (element-wise, GEMM, custom ops)
- Optimizing GPU memory access patterns (vectorized loads, TMA, shared memory)
- Building tensor core (MMA) kernels for Ampere/Hopper/Blackwell
- Integrating custom GPU kernels with PyTorch or JAX
- Prototyping high-performance kernels without C++ metaprogramming
Symptoms (wrong tool otherwise):
- Need shared memory coordination or tensor core MMA → use CuTe DSL (not Triton for complex patterns)
- Need simple element-wise ops with no shared memory → CuTe DSL or Triton both work
- Need to call existing CUTLASS C++ kernels → use CUTLASS C++ APIs instead
- Need reductions, scans, or non-GEMM collective ops → consider CUB/Thrust
Keywords: cute, cutlass, cute.jit, cute.kernel, from_dlpack, zipped_divide,
TiledMMA, TiledCopy, TMA, WGMMA, tcgen05, pipeline, mbarrier
Requirements
| Requirement |
Detail |
| Platform |
Linux x86_64 only |
| Python |
3.10–3.13 |
| GPU |
NVIDIA Ampere+ (SM80, SM90, SM100) |
| CUDA Driver |
≥ 575.51.03 (Toolkit 12.9 compat) |
| Install |
pip install nvidia-cutlass-dsl |
| Optional |
apache-tvm-ffi, torch-c-dlpack-ext |
Workflows
Workflow 0: Starting from Examples (Recommended)
For any non-trivial kernel (GEMM, attention, pipelined, fused ops), start by
finding the most similar existing example to use as a starting point — study
its structure, then rework it for your use case. Do not copy examples verbatim;
they target specific dtypes, architectures, and problem shapes that likely differ.
Pick the closest example from the index below.
Prefer examples matching the target GPU architecture (check with
torch.cuda.get_device_capability()) when the operation is similar.
Fetch via web_fetch with base URL
https://raw.githubusercontent.com/NVIDIA/cutlass/main/examples/python/CuTeDSL
| Operation |
Arch |
Example path (append to base URL) |
| Element-wise add |
SM80 |
ampere/elementwise_add.py |
| Element-wise + autotune |
SM80 |
ampere/elementwise_add_autotune.py |
| Element-wise apply |
SM80 |
ampere/elementwise_apply.py |
| SGEMM (scalar) |
SM80 |
ampere/sgemm.py |
| Tensor-core GEMM |
SM80 |
ampere/tensorop_gemm.py |
| Flash Attention v2 |
SM80 |
ampere/flash_attention_v2.py |
| HSTU Attention |
SM80 |
ampere/hstu_attention.py |
| Shared memory allocator |
SM80 |
ampere/smem_allocator.py |
| CTA norm (LayerNorm) |
SM90 |
hopper/cta_norm.py |
| Dense GEMM |
SM90 |
hopper/dense_gemm.py |
| Dense GEMM persistent |
SM90 |
hopper/dense_gemm_persistent.py |
| Flash MHA |
SM90 |
hopper/fmha.py |
| Dense GEMM |
SM100 |
blackwell/dense_gemm.py |
| Dense GEMM persistent |
SM100 |
blackwell/dense_gemm_persistent.py |
| Dense GEMM + alpha/beta |
SM100 |
blackwell/dense_gemm_alpha_beta_persistent.py |
| RMSNorm |
SM100 |
blackwell/rmsnorm.py |
| Reduce |
SM100 |
blackwell/reduce.py |
| Flash MHA |
SM100 |
blackwell/fmha.py |
| Grouped GEMM |
SM100 |
blackwell/grouped_gemm.py |
| Mamba2 SSD |
SM100 |
blackwell/mamba2_ssd/ |
| GEMM tutorial (notebook) |
SM100 |
notebooks/tour_to_sol_gemm.ipynb |
Example: To fetch the Hopper dense GEMM:
web_fetch https://raw.githubusercontent.com/NVIDIA/cutlass/main/examples/python/CuTeDSL/hopper/dense_gemm.py
Read reference materials first — before diving into example code, read
the relevant references/ docs to understand the patterns and APIs:
- For GEMM:
references/patterns-gemm.md (3-level tiling, epilogue fusion,
cute.compile with mark_layout_dynamic, shared memory layouts)
- For reductions:
references/patterns-reduction.md (warp reductions,
cute.compile cache pattern)
- For element-wise:
references/patterns-elementwise.md (variations A–E)
- Always:
references/api-arch.md (available APIs, arch-specific caveats)
This gives you the conceptual foundation so you can rework the example
intelligently rather than trying to copy-paste complex pipelines.
Fetch and study the example source — read for structure, not to copy:
- Identify: decorators, tiling strategy, shared memory usage, mainloop flow
- Note which dtype/arch it targets (many examples are fp16/bf16-specific)
- Check if it uses APIs tied to a specific arch (TMA → SM90+, tcgen05 → SM100)
Rework for the user's workload (do not copy-paste):
- Change shapes, data types, tile sizes to match requirements
- Replace compute logic (epilogue, activation fusion) as needed
- If dtype differs (e.g., example is fp16, need fp32), expect vectorization
and layout changes — the scalar-loop patterns in
references/ may be a
better starting point than adapting a vectorized example
- Runtime wrapper must be lightweight:
kernel_fn() should only call
from_dlpack() + the compiled kernel. Never allocate intermediate tensors,
copy data, or re-compile per call — these belong in one-time setup
- Apply optimizations from this skill's reference docs
⛔ Blackwell/Hopper GEMM + extra tensors — STOP:
If the target GPU is SM90+ (Hopper/Blackwell) and the GEMM requires
extra tensors beyond A, B, C in the epilogue (e.g., bias vector, activation
inputs), do not attempt it. These examples use TMA descriptors for all
data movement — adding tensors requires modifying TMA descriptor setup,
which is prohibitively complex. Instead, tell the user this limitation and
suggest a two-kernel approach: run the GEMM kernel as-is, then apply
bias + activation in a separate element-wise kernel (Workflow 1).
Plain GEMM (just A×B→C with scalar alpha/beta) on Hopper/Blackwell is fine.
Validate and benchmark using companion scripts:
python scripts/verify_kernel.py kernel.py --rtol 1e-3 --atol 1e-3
python scripts/benchmark_kernel.py kernel.py
The kernel file must export kernel_fn, reference_fn, and get_inputs().
When to skip examples: Pure element-wise operations (Workflow 1) have
complete patterns in references/patterns-elementwise.md — no need to fetch
external examples.
Reduction kernels (softmax, layernorm, RMSNorm): Use
references/patterns-reduction.md which provides complete, proven patterns
for float32 reductions using scalar loops + butterfly shuffle + shared memory.
Workflow 1: Element-wise Kernel
For unary/binary/in-place operations that map inputs to outputs 1:1.
- Determine kernel structure: inputs/outputs count, tensor rank, target arch
- Select pattern from
references/patterns-elementwise.md (Variations A–E)
- Write kernel applying all four invariant principles:
- P1:
from_dlpack(tensor, assumed_align=16) for vector loads
- P2: Derive
vec_size from element_type.width
- P3:
cute.zipped_divide(mA, tiler) for coalesced access
- P4:
cutlass.dynamic_expr(thread_idx < total) for bounds
- Critical rules: No early return, no
a * 2 (use a + a), no cute.math.sigmoid
- Pre-compile with
cute.compile(): Always pre-compile the kernel once
using cute.compile() so that kernel_fn calls the compiled object, not
@cute.jit directly. Without pre-compilation, every call recompiles
(~20-50ms overhead). Use .mark_layout_dynamic() so a single compiled
kernel handles arbitrary input shapes without recompilation:# Compile once with dynamic layouts — works for any shape
fake_x = from_dlpack(torch.empty(1, 1, dtype=torch.float16, device="cuda"),
assumed_align=16).mark_layout_dynamic()
fake_out = from_dlpack(torch.empty(1, 1, dtype=torch.float16, device="cuda"),
assumed_align=16).mark_layout_dynamic()
compiled_kernel = cute.compile(host_fn, fake_x, fake_out)
def kernel_fn(x):
out = torch.empty_like(x)
compiled_kernel(from_dlpack(x, assumed_align=16).mark_layout_dynamic(),
from_dlpack(out, assumed_align=16).mark_layout_dynamic())
return out
- Verify correctness using companion script:
python scripts/verify_kernel.py kernel.py --rtol 1e-3 --atol 1e-3
The kernel file must export kernel_fn, reference_fn, and get_inputs().
- Benchmark using companion script:
python scripts/benchmark_kernel.py kernel.py
Workflow 2: GEMM Kernel
For matrix multiplication with tiling, shared memory, and tensor cores.
- Define problem: shapes (M, N, K), data types, target architecture
- Choose tiling: CTA tile (bM, bN, bK), pipeline stages, cluster shape
- Three-level partitioning (see
references/patterns-gemm.md):
- Level 1: CTA tiling with
local_tile()
- Level 2: Copy partitioning (global → shared) with
TiledCopy
- Level 3: Compute partitioning (shared → register) with
TiledMMA
- Shared memory: Use swizzled layouts (
make_smem_layout_atom) to avoid bank conflicts
- Mainloop: K-tile loop with copy → sync → MMA → sync
- Pipeline: Use
PipelineTmaAsync (Hopper) or PipelineTmaUmma (Blackwell).
⚠️ TMA-based pipelines manage data movement via TMA descriptors — adding
extra tensors (bias, activation inputs) to the epilogue requires modifying
descriptor setup, which is prohibitively complex. See the stop condition in
Workflow 0 step 4.
- Epilogue: Predicated store with alpha/beta scaling
- Pre-compile with
cute.compile(): Always pre-compile the GEMM kernel
so kernel_fn calls the compiled object, not @cute.jit directly.
Without pre-compilation, every call recompiles (~20-50ms overhead).
- Autotune: Search over tile sizes, cluster shapes, pipeline depths
Workflow 3: Framework Integration
For wrapping CuTe DSL kernels as PyTorch/JAX custom operators.
- Write kernel using Workflow 1 or 2
- Create wrapper: Accept
torch.Tensor, convert via from_dlpack, call host fn
- For production: Compile with TVM FFI for zero-overhead tensor passing:
compiled = cute.compile(host_fn, *fake_tensors, options="--enable-tvm-ffi")
compiled(torch_a, torch_b) # Direct torch.Tensor, no from_dlpack
- For deployment: Use AOT compilation → export to
.o → load at runtime
Workflow 4: Debugging & Profiling
- Set environment:
CUTE_DSL_PRINT_IR=1, CUTE_DSL_KEEP_PTX=1
- Use
cute.printf() for runtime values (not Python print)
- Inspect generated code:
compiled.__ptx__, compiled.__mlir__
- Profile: Enable
CUTE_DSL_LINEINFO=1, use Nsight Compute/Systems
- Debug memory: Run with
compute-sanitizer python script.py
Output Formats
A typical CuTe DSL kernel project:
kernel_dir/
kernel.py # @cute.kernel + @cute.jit functions
test_kernel.py # Correctness test vs PyTorch reference
bench_kernel.py # Benchmark with cute.compile() setup
Success indicators:
- Correctness test passes (
torch.testing.assert_close)
- Nsight shows vector loads (LDG.128/LDG.256), not scalar loads
- For GEMM: tensor core utilization > 80% in Nsight Compute
Companion Script Contract
Kernel files used with scripts/verify_kernel.py and scripts/benchmark_kernel.py
must export three names:
kernel_fn(*inputs) — the CuTe DSL kernel wrapper (calls cute.compile + runs kernel)
reference_fn(*inputs) — PyTorch reference implementation (same signature)
get_inputs() — returns a list of CUDA tensors for testing
# Example kernel.py contract
import torch
import cutlass.cute as cute
from cutlass.cute.runtime import from_dlpack
def kernel_fn(x):
out = torch.empty_like(x)
# ... call compiled cute kernel ...
return out
def reference_fn(x):
return torch.nn.functional.gelu(x)
def get_inputs():
return [torch.randn(1024, 512, dtype=torch.float16, device="cuda")]
Examples
Example: 2D Unary Element-wise (ReLU)
import torch, cutlass, cutlass.cute as cute
from cutlass.cute.runtime import from_dlpack
@cute.kernel
def relu_kernel(gA: cute.Tensor, gC: cute.Tensor):
tidx, _, _ = cute.arch.thread_idx()
bidx, _, _ = cute.arch.block_idx()
bdim, _, _ = cute.arch.block_dim()
idx = bidx * bdim + tidx
m, n = gA.shape[1]
total = m * n
if cutlass.dynamic_expr(idx < total):
a = gA[(None, (idx // n, idx % n))].load()
gC[(None, (idx // n, idx % n))] = cute.where(a > 0, a, 0)
@cute.jit
def relu_host(mA: cute.Tensor, mC: cute.Tensor):
vec = 16 // (mA.element_type.width // 8)
gA = cute.zipped_divide(mA, (1, vec))
gC = cute.zipped_divide(mC, (1, vec))
T = 256
N = cute.size(gA.shape[1])
relu_kernel(gA, gC).launch(grid=((N+T-1)//T,1,1), block=(T,1,1))
x = torch.randn(1024, 512, dtype=torch.float16, device="cuda")
out = torch.empty_like(x)
relu_host(from_dlpack(x, assumed_align=16), from_dlpack(out, assumed_align=16))
Error Handling
| Error |
Cause |
Fix |
MLIR function requires a Context |
Called @kernel from Python |
Launch via @cute.jit host function |
DSLAstPreprocessorError on return |
Early return in @kernel |
Use if cutlass.dynamic_expr(cond): |
| Type mismatch on store |
a * 2 promotes FP16→FP32 |
Use a + a or .to(cutlass.Float16) |
could not get source code |
Kernel in exec() context |
Write to file and import |
| Scalar loads in Nsight |
Missing alignment hint |
Add assumed_align=16 to from_dlpack |
Missing required argument |
Not all @jit params passed |
Pass ALL declared parameters |
AttributeError: sigmoid |
No cute.math.sigmoid |
Use 1.0/(1.0+cute.math.exp(-x)) |
See references/troubleshooting.md for the full error table and limitations.
Debugging rule: Never delete kernel.py during debugging. Use backup_file
to save a checkpoint, then edit_file to iterate. If stuck, revert_file to
restore the backup. A partially-working kernel is always better than no kernel.
Finding More Information
Tier 1: This File (SKILL.md)
Workflows above cover element-wise kernels, GEMM, framework integration, and
debugging. Search this file first for procedural questions.
Tier 2: references/ Directory
Grep for keywords across references/. Headers are grep-friendly.
| File |
Content |
concepts-architecture.md |
Core abstractions, terminology, compilation pipeline |
concepts-layouts.md |
Layout algebra: composition, complement, divide, swizzle |
concepts-tensors.md |
Tensor types, partitioning, tiling, predication |
concepts-mma.md |
MMA atoms, TiledMMA, per-architecture tensor core ops |
patterns-getting-started.md |
Installation, decorators, first kernel walkthrough |
patterns-elementwise.md |
Invariant principles, pattern variations, reference impl |
patterns-gemm.md |
3-level tiling, shared memory, pipelining, autotuning |
patterns-memory.md |
from_dlpack, TMA, cp.async, TMEM, copy atoms |
patterns-compilation.md |
Control flow, JIT caching, TVM FFI, AOT compilation |
patterns-pipeline.md |
Producer-consumer, pipeline classes, barriers, warp specialization |
api-core.md |
cute module: layouts, tensors, math, copy, gemm, printing |
api-arch.md |
cute.arch: thread indexing, sync, atomics, memory ops |
api-nvgpu.md |
cute.nvgpu: warp/warpgroup/cpasync/tcgen05 MMA and copy |
api-runtime-utils.md |
Runtime: from_dlpack, fake tensors, utils, schedulers |
troubleshooting.md |
Debugging, env vars, common errors, limitations, FAQ |
How to search: Grep for your keyword across references/. Read only the
file and section that Grep points to.
Tier 3: Original Documentation
If Tiers 1–2 don't answer, consult the source:
1---2name: nvidia-tensorrt-llm-kernel-cute-writing3description: 'Write and implement GPU kernels using NVIDIA CuTe DSL (CUTLASS 4.x Python4 API) — NOT for Triton, CUDA C++, or conceptual explanations. Trigger only when the5 user wants to write or implement a kernel, not when asking questions about CuTe6 DSL concepts or layouts. CuTe DSL uses cute.jit/cute.kernel decorators and cutlass.cute7 imports. Covers element-wise kernels, GEMM patterns, reductions, memory hierarchy8 (global/shared/register/TMA), MMA tensor core operations, software pipelining, and9 framework integration.1011 '12license: Apache-2.013metadata:14 author: NVIDIA Corporation15---1617# CuTe DSL1819CuTe DSL is a Python-based domain-specific language for GPU kernel development,20part of CUTLASS 4.x. It provides Python abstractions over CUTLASS C++ templates21with JIT compilation to optimized CUDA kernels via MLIR and ptxas.2223## When to Use2425**Triggers:**26- Writing CUDA kernels in Python (element-wise, GEMM, custom ops)27- Optimizing GPU memory access patterns (vectorized loads, TMA, shared memory)28- Building tensor core (MMA) kernels for Ampere/Hopper/Blackwell29- Integrating custom GPU kernels with PyTorch or JAX30- Prototyping high-performance kernels without C++ metaprogramming3132**Symptoms (wrong tool otherwise):**33- Need shared memory coordination or tensor core MMA → use CuTe DSL (not Triton for complex patterns)34- Need simple element-wise ops with no shared memory → CuTe DSL or Triton both work35- Need to call existing CUTLASS C++ kernels → use CUTLASS C++ APIs instead36- Need reductions, scans, or non-GEMM collective ops → consider CUB/Thrust3738**Keywords:** cute, cutlass, cute.jit, cute.kernel, from_dlpack, zipped_divide,39TiledMMA, TiledCopy, TMA, WGMMA, tcgen05, pipeline, mbarrier4041## Requirements4243| Requirement | Detail |44|-------------|--------|45| Platform | Linux x86_64 only |46| Python | 3.10–3.13 |47| GPU | NVIDIA Ampere+ (SM80, SM90, SM100) |48| CUDA Driver | ≥ 575.51.03 (Toolkit 12.9 compat) |49| Install | `pip install nvidia-cutlass-dsl` |50| Optional | `apache-tvm-ffi`, `torch-c-dlpack-ext` |5152## Workflows5354### Workflow 0: Starting from Examples (Recommended)5556For any non-trivial kernel (GEMM, attention, pipelined, fused ops), start by57finding the most similar existing example to use as a **starting point** — study58its structure, then rework it for your use case. Do not copy examples verbatim;59they target specific dtypes, architectures, and problem shapes that likely differ.60611. **Pick the closest example** from the index below.62 **Prefer examples matching the target GPU architecture** (check with63 `torch.cuda.get_device_capability()`) when the operation is similar.6465 Fetch via `web_fetch` with base URL66 `https://raw.githubusercontent.com/NVIDIA/cutlass/main/examples/python/CuTeDSL`6768 | Operation | Arch | Example path (append to base URL) |69 |-----------|------|-----------------------------------|70 | Element-wise add | SM80 | `ampere/elementwise_add.py` |71 | Element-wise + autotune | SM80 | `ampere/elementwise_add_autotune.py` |72 | Element-wise apply | SM80 | `ampere/elementwise_apply.py` |73 | SGEMM (scalar) | SM80 | `ampere/sgemm.py` |74 | Tensor-core GEMM | SM80 | `ampere/tensorop_gemm.py` |75 | Flash Attention v2 | SM80 | `ampere/flash_attention_v2.py` |76 | HSTU Attention | SM80 | `ampere/hstu_attention.py` |77 | Shared memory allocator | SM80 | `ampere/smem_allocator.py` |78 | CTA norm (LayerNorm) | SM90 | `hopper/cta_norm.py` |79 | Dense GEMM | SM90 | `hopper/dense_gemm.py` |80 | Dense GEMM persistent | SM90 | `hopper/dense_gemm_persistent.py` |81 | Flash MHA | SM90 | `hopper/fmha.py` |82 | Dense GEMM | SM100 | `blackwell/dense_gemm.py` |83 | Dense GEMM persistent | SM100 | `blackwell/dense_gemm_persistent.py` |84 | Dense GEMM + alpha/beta | SM100 | `blackwell/dense_gemm_alpha_beta_persistent.py` |85 | RMSNorm | SM100 | `blackwell/rmsnorm.py` |86 | Reduce | SM100 | `blackwell/reduce.py` |87 | Flash MHA | SM100 | `blackwell/fmha.py` |88 | Grouped GEMM | SM100 | `blackwell/grouped_gemm.py` |89 | Mamba2 SSD | SM100 | `blackwell/mamba2_ssd/` |90 | GEMM tutorial (notebook) | SM100 | `notebooks/tour_to_sol_gemm.ipynb` |9192 **Example:** To fetch the Hopper dense GEMM:93 ```bash94 web_fetch https://raw.githubusercontent.com/NVIDIA/cutlass/main/examples/python/CuTeDSL/hopper/dense_gemm.py95 ```96972. **Read reference materials first** — before diving into example code, read98 the relevant `references/` docs to understand the patterns and APIs:99 - For GEMM: `references/patterns-gemm.md` (3-level tiling, epilogue fusion,100 `cute.compile` with `mark_layout_dynamic`, shared memory layouts)101 - For reductions: `references/patterns-reduction.md` (warp reductions,102 `cute.compile` cache pattern)103 - For element-wise: `references/patterns-elementwise.md` (variations A–E)104 - Always: `references/api-arch.md` (available APIs, arch-specific caveats)105106 This gives you the conceptual foundation so you can rework the example107 intelligently rather than trying to copy-paste complex pipelines.1081093. **Fetch and study the example source** — read for structure, not to copy:110 - Identify: decorators, tiling strategy, shared memory usage, mainloop flow111 - Note which dtype/arch it targets (many examples are fp16/bf16-specific)112 - Check if it uses APIs tied to a specific arch (TMA → SM90+, tcgen05 → SM100)1131144. **Rework for the user's workload** (do not copy-paste):115 - Change shapes, data types, tile sizes to match requirements116 - Replace compute logic (epilogue, activation fusion) as needed117 - If dtype differs (e.g., example is fp16, need fp32), expect vectorization118 and layout changes — the scalar-loop patterns in `references/` may be a119 better starting point than adapting a vectorized example120 - **Runtime wrapper must be lightweight**: `kernel_fn()` should only call121 `from_dlpack()` + the compiled kernel. Never allocate intermediate tensors,122 copy data, or re-compile per call — these belong in one-time setup123 - Apply optimizations from this skill's reference docs124125 **⛔ Blackwell/Hopper GEMM + extra tensors — STOP:**126 If the target GPU is SM90+ (Hopper/Blackwell) **and** the GEMM requires127 extra tensors beyond A, B, C in the epilogue (e.g., bias vector, activation128 inputs), **do not attempt it**. These examples use TMA descriptors for all129 data movement — adding tensors requires modifying TMA descriptor setup,130 which is prohibitively complex. Instead, tell the user this limitation and131 suggest a **two-kernel approach**: run the GEMM kernel as-is, then apply132 bias + activation in a separate element-wise kernel (Workflow 1).133 Plain GEMM (just A×B→C with scalar alpha/beta) on Hopper/Blackwell is fine.1341355. **Validate and benchmark** using companion scripts:136 ```bash137 python scripts/verify_kernel.py kernel.py --rtol 1e-3 --atol 1e-3138 python scripts/benchmark_kernel.py kernel.py139 ```140 The kernel file must export `kernel_fn`, `reference_fn`, and `get_inputs()`.141142**When to skip examples:** Pure element-wise operations (Workflow 1) have143complete patterns in `references/patterns-elementwise.md` — no need to fetch144external examples.145146**Reduction kernels** (softmax, layernorm, RMSNorm): Use147`references/patterns-reduction.md` which provides complete, proven patterns148for float32 reductions using scalar loops + butterfly shuffle + shared memory.149150### Workflow 1: Element-wise Kernel151152For unary/binary/in-place operations that map inputs to outputs 1:1.1531541. **Determine kernel structure**: inputs/outputs count, tensor rank, target arch1552. **Select pattern** from `references/patterns-elementwise.md` (Variations A–E)1563. **Write kernel** applying all four invariant principles:157 - P1: `from_dlpack(tensor, assumed_align=16)` for vector loads158 - P2: Derive `vec_size` from `element_type.width`159 - P3: `cute.zipped_divide(mA, tiler)` for coalesced access160 - P4: `cutlass.dynamic_expr(thread_idx < total)` for bounds1614. **Critical rules**: No early return, no `a * 2` (use `a + a`), no `cute.math.sigmoid`1625. **Pre-compile with `cute.compile()`**: Always pre-compile the kernel once163 using `cute.compile()` so that `kernel_fn` calls the compiled object, not164 `@cute.jit` directly. Without pre-compilation, every call recompiles165 (~20-50ms overhead). Use `.mark_layout_dynamic()` so a single compiled166 kernel handles arbitrary input shapes without recompilation:167 ```python168 # Compile once with dynamic layouts — works for any shape169 fake_x = from_dlpack(torch.empty(1, 1, dtype=torch.float16, device="cuda"),170 assumed_align=16).mark_layout_dynamic()171 fake_out = from_dlpack(torch.empty(1, 1, dtype=torch.float16, device="cuda"),172 assumed_align=16).mark_layout_dynamic()173 compiled_kernel = cute.compile(host_fn, fake_x, fake_out)174175 def kernel_fn(x):176 out = torch.empty_like(x)177 compiled_kernel(from_dlpack(x, assumed_align=16).mark_layout_dynamic(),178 from_dlpack(out, assumed_align=16).mark_layout_dynamic())179 return out180 ```1816. **Verify correctness** using companion script:182 ```bash183 python scripts/verify_kernel.py kernel.py --rtol 1e-3 --atol 1e-3184 ```185 The kernel file must export `kernel_fn`, `reference_fn`, and `get_inputs()`.1867. **Benchmark** using companion script:187 ```bash188 python scripts/benchmark_kernel.py kernel.py189 ```190191### Workflow 2: GEMM Kernel192193For matrix multiplication with tiling, shared memory, and tensor cores.1941951. **Define problem**: shapes (M, N, K), data types, target architecture1962. **Choose tiling**: CTA tile (bM, bN, bK), pipeline stages, cluster shape1973. **Three-level partitioning** (see `references/patterns-gemm.md`):198 - Level 1: CTA tiling with `local_tile()`199 - Level 2: Copy partitioning (global → shared) with `TiledCopy`200 - Level 3: Compute partitioning (shared → register) with `TiledMMA`2014. **Shared memory**: Use swizzled layouts (`make_smem_layout_atom`) to avoid bank conflicts2025. **Mainloop**: K-tile loop with copy → sync → MMA → sync2036. **Pipeline**: Use `PipelineTmaAsync` (Hopper) or `PipelineTmaUmma` (Blackwell).204 ⚠️ TMA-based pipelines manage data movement via TMA descriptors — adding205 extra tensors (bias, activation inputs) to the epilogue requires modifying206 descriptor setup, which is prohibitively complex. See the stop condition in207 Workflow 0 step 4.2087. **Epilogue**: Predicated store with alpha/beta scaling2098. **Pre-compile with `cute.compile()`**: Always pre-compile the GEMM kernel210 so `kernel_fn` calls the compiled object, not `@cute.jit` directly.211 Without pre-compilation, every call recompiles (~20-50ms overhead).2129. **Autotune**: Search over tile sizes, cluster shapes, pipeline depths213214### Workflow 3: Framework Integration215216For wrapping CuTe DSL kernels as PyTorch/JAX custom operators.2172181. **Write kernel** using Workflow 1 or 22192. **Create wrapper**: Accept `torch.Tensor`, convert via `from_dlpack`, call host fn2203. **For production**: Compile with TVM FFI for zero-overhead tensor passing:221 ```python222 compiled = cute.compile(host_fn, *fake_tensors, options="--enable-tvm-ffi")223 compiled(torch_a, torch_b) # Direct torch.Tensor, no from_dlpack224 ```2254. **For deployment**: Use AOT compilation → export to `.o` → load at runtime226227### Workflow 4: Debugging & Profiling2282291. **Set environment**: `CUTE_DSL_PRINT_IR=1`, `CUTE_DSL_KEEP_PTX=1`2302. **Use `cute.printf()`** for runtime values (not Python `print`)2313. **Inspect generated code**: `compiled.__ptx__`, `compiled.__mlir__`2324. **Profile**: Enable `CUTE_DSL_LINEINFO=1`, use Nsight Compute/Systems2335. **Debug memory**: Run with `compute-sanitizer python script.py`234235## Output Formats236237A typical CuTe DSL kernel project:238239```240kernel_dir/241 kernel.py # @cute.kernel + @cute.jit functions242 test_kernel.py # Correctness test vs PyTorch reference243 bench_kernel.py # Benchmark with cute.compile() setup244```245246**Success indicators:**247- Correctness test passes (`torch.testing.assert_close`)248- Nsight shows vector loads (LDG.128/LDG.256), not scalar loads249- For GEMM: tensor core utilization > 80% in Nsight Compute250251## Companion Script Contract252253Kernel files used with `scripts/verify_kernel.py` and `scripts/benchmark_kernel.py`254must export three names:255256- `kernel_fn(*inputs)` — the CuTe DSL kernel wrapper (calls `cute.compile` + runs kernel)257- `reference_fn(*inputs)` — PyTorch reference implementation (same signature)258- `get_inputs()` — returns a list of CUDA tensors for testing259260```python261# Example kernel.py contract262import torch263import cutlass.cute as cute264from cutlass.cute.runtime import from_dlpack265266def kernel_fn(x):267 out = torch.empty_like(x)268 # ... call compiled cute kernel ...269 return out270271def reference_fn(x):272 return torch.nn.functional.gelu(x)273274def get_inputs():275 return [torch.randn(1024, 512, dtype=torch.float16, device="cuda")]276```277278## Examples279280### Example: 2D Unary Element-wise (ReLU)281282```python283import torch, cutlass, cutlass.cute as cute284from cutlass.cute.runtime import from_dlpack285286@cute.kernel287def relu_kernel(gA: cute.Tensor, gC: cute.Tensor):288 tidx, _, _ = cute.arch.thread_idx()289 bidx, _, _ = cute.arch.block_idx()290 bdim, _, _ = cute.arch.block_dim()291 idx = bidx * bdim + tidx292 m, n = gA.shape[1]293 total = m * n294 if cutlass.dynamic_expr(idx < total):295 a = gA[(None, (idx // n, idx % n))].load()296 gC[(None, (idx // n, idx % n))] = cute.where(a > 0, a, 0)297298@cute.jit299def relu_host(mA: cute.Tensor, mC: cute.Tensor):300 vec = 16 // (mA.element_type.width // 8)301 gA = cute.zipped_divide(mA, (1, vec))302 gC = cute.zipped_divide(mC, (1, vec))303 T = 256304 N = cute.size(gA.shape[1])305 relu_kernel(gA, gC).launch(grid=((N+T-1)//T,1,1), block=(T,1,1))306307x = torch.randn(1024, 512, dtype=torch.float16, device="cuda")308out = torch.empty_like(x)309relu_host(from_dlpack(x, assumed_align=16), from_dlpack(out, assumed_align=16))310```311312## Error Handling313314| Error | Cause | Fix |315|-------|-------|-----|316| `MLIR function requires a Context` | Called @kernel from Python | Launch via @cute.jit host function |317| `DSLAstPreprocessorError` on return | Early return in @kernel | Use `if cutlass.dynamic_expr(cond):` |318| Type mismatch on store | `a * 2` promotes FP16→FP32 | Use `a + a` or `.to(cutlass.Float16)` |319| `could not get source code` | Kernel in `exec()` context | Write to file and import |320| Scalar loads in Nsight | Missing alignment hint | Add `assumed_align=16` to `from_dlpack` |321| `Missing required argument` | Not all @jit params passed | Pass ALL declared parameters |322| `AttributeError: sigmoid` | No `cute.math.sigmoid` | Use `1.0/(1.0+cute.math.exp(-x))` |323324See `references/troubleshooting.md` for the full error table and limitations.325326**Debugging rule:** Never delete kernel.py during debugging. Use `backup_file`327to save a checkpoint, then `edit_file` to iterate. If stuck, `revert_file` to328restore the backup. A partially-working kernel is always better than no kernel.329330## Finding More Information331332### Tier 1: This File (SKILL.md)333334Workflows above cover element-wise kernels, GEMM, framework integration, and335debugging. Search this file first for procedural questions.336337### Tier 2: references/ Directory338339Grep for keywords across `references/`. Headers are grep-friendly.340341| File | Content |342|------|---------|343| `concepts-architecture.md` | Core abstractions, terminology, compilation pipeline |344| `concepts-layouts.md` | Layout algebra: composition, complement, divide, swizzle |345| `concepts-tensors.md` | Tensor types, partitioning, tiling, predication |346| `concepts-mma.md` | MMA atoms, TiledMMA, per-architecture tensor core ops |347| `patterns-getting-started.md` | Installation, decorators, first kernel walkthrough |348| `patterns-elementwise.md` | Invariant principles, pattern variations, reference impl |349| `patterns-gemm.md` | 3-level tiling, shared memory, pipelining, autotuning |350| `patterns-memory.md` | from_dlpack, TMA, cp.async, TMEM, copy atoms |351| `patterns-compilation.md` | Control flow, JIT caching, TVM FFI, AOT compilation |352| `patterns-pipeline.md` | Producer-consumer, pipeline classes, barriers, warp specialization |353| `api-core.md` | cute module: layouts, tensors, math, copy, gemm, printing |354| `api-arch.md` | cute.arch: thread indexing, sync, atomics, memory ops |355| `api-nvgpu.md` | cute.nvgpu: warp/warpgroup/cpasync/tcgen05 MMA and copy |356| `api-runtime-utils.md` | Runtime: from_dlpack, fake tensors, utils, schedulers |357| `troubleshooting.md` | Debugging, env vars, common errors, limitations, FAQ |358359**How to search:** Grep for your keyword across `references/`. Read only the360file and section that Grep points to.361362### Tier 3: Original Documentation363364If Tiers 1–2 don't answer, consult the source:365- **Web**: https://docs.nvidia.com/cutlass/latest/366- **GitHub**: https://github.com/NVIDIA/cutlass367- Fetch specific doc pages or search for "CUTLASS CuTe DSL <topic>"368- Consider distilling the answer back into references/