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 Python API) — NOT for Triton, CUDA C++, or conceptual explanations. Trigger only when the user wants to write or implement a kernel, not when asking questions about CuTe DSL concepts or layouts. CuTe DSL uses cute.jit/cute.kernel decorators and cutlass.cute imports. Covers element-wise kernels, GEMM patterns, reductions, memory hierarchy (global/shared/register/TMA), MMA tensor core operations, software pipelining, and framework integration.4license: Apache-2.05---67# CuTe DSL89CuTe DSL is a Python-based domain-specific language for GPU kernel development,10part of CUTLASS 4.x. It provides Python abstractions over CUTLASS C++ templates11with JIT compilation to optimized CUDA kernels via MLIR and ptxas.1213## When to Use1415**Triggers:**16- Writing CUDA kernels in Python (element-wise, GEMM, custom ops)17- Optimizing GPU memory access patterns (vectorized loads, TMA, shared memory)18- Building tensor core (MMA) kernels for Ampere/Hopper/Blackwell19- Integrating custom GPU kernels with PyTorch or JAX20- Prototyping high-performance kernels without C++ metaprogramming2122**Symptoms (wrong tool otherwise):**23- Need shared memory coordination or tensor core MMA → use CuTe DSL (not Triton for complex patterns)24- Need simple element-wise ops with no shared memory → CuTe DSL or Triton both work25- Need to call existing CUTLASS C++ kernels → use CUTLASS C++ APIs instead26- Need reductions, scans, or non-GEMM collective ops → consider CUB/Thrust2728**Keywords:** cute, cutlass, cute.jit, cute.kernel, from_dlpack, zipped_divide,29TiledMMA, TiledCopy, TMA, WGMMA, tcgen05, pipeline, mbarrier3031## Requirements3233| Requirement | Detail |34|-------------|--------|35| Platform | Linux x86_64 only |36| Python | 3.10–3.13 |37| GPU | NVIDIA Ampere+ (SM80, SM90, SM100) |38| CUDA Driver | ≥ 575.51.03 (Toolkit 12.9 compat) |39| Install | `pip install nvidia-cutlass-dsl` |40| Optional | `apache-tvm-ffi`, `torch-c-dlpack-ext` |4142## Workflows4344### Workflow 0: Starting from Examples (Recommended)4546For any non-trivial kernel (GEMM, attention, pipelined, fused ops), start by47finding the most similar existing example to use as a **starting point** — study48its structure, then rework it for your use case. Do not copy examples verbatim;49they target specific dtypes, architectures, and problem shapes that likely differ.50511. **Pick the closest example** from the index below.52 **Prefer examples matching the target GPU architecture** (check with53 `torch.cuda.get_device_capability()`) when the operation is similar.5455 Fetch via `web_fetch` with base URL56 `https://raw.githubusercontent.com/NVIDIA/cutlass/main/examples/python/CuTeDSL`5758 | Operation | Arch | Example path (append to base URL) |59 |-----------|------|-----------------------------------|60 | Element-wise add | SM80 | `ampere/elementwise_add.py` |61 | Element-wise + autotune | SM80 | `ampere/elementwise_add_autotune.py` |62 | Element-wise apply | SM80 | `ampere/elementwise_apply.py` |63 | SGEMM (scalar) | SM80 | `ampere/sgemm.py` |64 | Tensor-core GEMM | SM80 | `ampere/tensorop_gemm.py` |65 | Flash Attention v2 | SM80 | `ampere/flash_attention_v2.py` |66 | HSTU Attention | SM80 | `ampere/hstu_attention.py` |67 | Shared memory allocator | SM80 | `ampere/smem_allocator.py` |68 | CTA norm (LayerNorm) | SM90 | `hopper/cta_norm.py` |69 | Dense GEMM | SM90 | `hopper/dense_gemm.py` |70 | Dense GEMM persistent | SM90 | `hopper/dense_gemm_persistent.py` |71 | Flash MHA | SM90 | `hopper/fmha.py` |72 | Dense GEMM | SM100 | `blackwell/dense_gemm.py` |73 | Dense GEMM persistent | SM100 | `blackwell/dense_gemm_persistent.py` |74 | Dense GEMM + alpha/beta | SM100 | `blackwell/dense_gemm_alpha_beta_persistent.py` |75 | RMSNorm | SM100 | `blackwell/rmsnorm.py` |76 | Reduce | SM100 | `blackwell/reduce.py` |77 | Flash MHA | SM100 | `blackwell/fmha.py` |78 | Grouped GEMM | SM100 | `blackwell/grouped_gemm.py` |79 | Mamba2 SSD | SM100 | `blackwell/mamba2_ssd/` |80 | GEMM tutorial (notebook) | SM100 | `notebooks/tour_to_sol_gemm.ipynb` |8182 **Example:** To fetch the Hopper dense GEMM:83 ```bash84 web_fetch https://raw.githubusercontent.com/NVIDIA/cutlass/main/examples/python/CuTeDSL/hopper/dense_gemm.py85 ```86872. **Read reference materials first** — before diving into example code, read88 the relevant `references/` docs to understand the patterns and APIs:89 - For GEMM: `references/patterns-gemm.md` (3-level tiling, epilogue fusion,90 `cute.compile` with `mark_layout_dynamic`, shared memory layouts)91 - For reductions: `references/patterns-reduction.md` (warp reductions,92 `cute.compile` cache pattern)93 - For element-wise: `references/patterns-elementwise.md` (variations A–E)94 - Always: `references/api-arch.md` (available APIs, arch-specific caveats)9596 This gives you the conceptual foundation so you can rework the example97 intelligently rather than trying to copy-paste complex pipelines.98993. **Fetch and study the example source** — read for structure, not to copy:100 - Identify: decorators, tiling strategy, shared memory usage, mainloop flow101 - Note which dtype/arch it targets (many examples are fp16/bf16-specific)102 - Check if it uses APIs tied to a specific arch (TMA → SM90+, tcgen05 → SM100)1031044. **Rework for the user's workload** (do not copy-paste):105 - Change shapes, data types, tile sizes to match requirements106 - Replace compute logic (epilogue, activation fusion) as needed107 - If dtype differs (e.g., example is fp16, need fp32), expect vectorization108 and layout changes — the scalar-loop patterns in `references/` may be a109 better starting point than adapting a vectorized example110 - **Runtime wrapper must be lightweight**: `kernel_fn()` should only call111 `from_dlpack()` + the compiled kernel. Never allocate intermediate tensors,112 copy data, or re-compile per call — these belong in one-time setup113 - Apply optimizations from this skill's reference docs114115 **⛔ Blackwell/Hopper GEMM + extra tensors — STOP:**116 If the target GPU is SM90+ (Hopper/Blackwell) **and** the GEMM requires117 extra tensors beyond A, B, C in the epilogue (e.g., bias vector, activation118 inputs), **do not attempt it**. These examples use TMA descriptors for all119 data movement — adding tensors requires modifying TMA descriptor setup,120 which is prohibitively complex. Instead, tell the user this limitation and121 suggest a **two-kernel approach**: run the GEMM kernel as-is, then apply122 bias + activation in a separate element-wise kernel (Workflow 1).123 Plain GEMM (just A×B→C with scalar alpha/beta) on Hopper/Blackwell is fine.1241255. **Validate and benchmark** using companion scripts:126 ```bash127 python scripts/verify_kernel.py kernel.py --rtol 1e-3 --atol 1e-3128 python scripts/benchmark_kernel.py kernel.py129 ```130 The kernel file must export `kernel_fn`, `reference_fn`, and `get_inputs()`.131132**When to skip examples:** Pure element-wise operations (Workflow 1) have133complete patterns in `references/patterns-elementwise.md` — no need to fetch134external examples.135136**Reduction kernels** (softmax, layernorm, RMSNorm): Use137`references/patterns-reduction.md` which provides complete, proven patterns138for float32 reductions using scalar loops + butterfly shuffle + shared memory.139140### Workflow 1: Element-wise Kernel141142For unary/binary/in-place operations that map inputs to outputs 1:1.1431441. **Determine kernel structure**: inputs/outputs count, tensor rank, target arch1452. **Select pattern** from `references/patterns-elementwise.md` (Variations A–E)1463. **Write kernel** applying all four invariant principles:147 - P1: `from_dlpack(tensor, assumed_align=16)` for vector loads148 - P2: Derive `vec_size` from `element_type.width`149 - P3: `cute.zipped_divide(mA, tiler)` for coalesced access150 - P4: `cutlass.dynamic_expr(thread_idx < total)` for bounds1514. **Critical rules**: No early return, no `a * 2` (use `a + a`), no `cute.math.sigmoid`1525. **Pre-compile with `cute.compile()`**: Always pre-compile the kernel once153 using `cute.compile()` so that `kernel_fn` calls the compiled object, not154 `@cute.jit` directly. Without pre-compilation, every call recompiles155 (~20-50ms overhead). Use `.mark_layout_dynamic()` so a single compiled156 kernel handles arbitrary input shapes without recompilation:157 ```python158 # Compile once with dynamic layouts — works for any shape159 fake_x = from_dlpack(torch.empty(1, 1, dtype=torch.float16, device="cuda"),160 assumed_align=16).mark_layout_dynamic()161 fake_out = from_dlpack(torch.empty(1, 1, dtype=torch.float16, device="cuda"),162 assumed_align=16).mark_layout_dynamic()163 compiled_kernel = cute.compile(host_fn, fake_x, fake_out)164165 def kernel_fn(x):166 out = torch.empty_like(x)167 compiled_kernel(from_dlpack(x, assumed_align=16).mark_layout_dynamic(),168 from_dlpack(out, assumed_align=16).mark_layout_dynamic())169 return out170 ```1716. **Verify correctness** using companion script:172 ```bash173 python scripts/verify_kernel.py kernel.py --rtol 1e-3 --atol 1e-3174 ```175 The kernel file must export `kernel_fn`, `reference_fn`, and `get_inputs()`.1767. **Benchmark** using companion script:177 ```bash178 python scripts/benchmark_kernel.py kernel.py179 ```180181### Workflow 2: GEMM Kernel182183For matrix multiplication with tiling, shared memory, and tensor cores.1841851. **Define problem**: shapes (M, N, K), data types, target architecture1862. **Choose tiling**: CTA tile (bM, bN, bK), pipeline stages, cluster shape1873. **Three-level partitioning** (see `references/patterns-gemm.md`):188 - Level 1: CTA tiling with `local_tile()`189 - Level 2: Copy partitioning (global → shared) with `TiledCopy`190 - Level 3: Compute partitioning (shared → register) with `TiledMMA`1914. **Shared memory**: Use swizzled layouts (`make_smem_layout_atom`) to avoid bank conflicts1925. **Mainloop**: K-tile loop with copy → sync → MMA → sync1936. **Pipeline**: Use `PipelineTmaAsync` (Hopper) or `PipelineTmaUmma` (Blackwell).194 ⚠️ TMA-based pipelines manage data movement via TMA descriptors — adding195 extra tensors (bias, activation inputs) to the epilogue requires modifying196 descriptor setup, which is prohibitively complex. See the stop condition in197 Workflow 0 step 4.1987. **Epilogue**: Predicated store with alpha/beta scaling1998. **Pre-compile with `cute.compile()`**: Always pre-compile the GEMM kernel200 so `kernel_fn` calls the compiled object, not `@cute.jit` directly.201 Without pre-compilation, every call recompiles (~20-50ms overhead).2029. **Autotune**: Search over tile sizes, cluster shapes, pipeline depths203204### Workflow 3: Framework Integration205206For wrapping CuTe DSL kernels as PyTorch/JAX custom operators.2072081. **Write kernel** using Workflow 1 or 22092. **Create wrapper**: Accept `torch.Tensor`, convert via `from_dlpack`, call host fn2103. **For production**: Compile with TVM FFI for zero-overhead tensor passing:211 ```python212 compiled = cute.compile(host_fn, *fake_tensors, options="--enable-tvm-ffi")213 compiled(torch_a, torch_b) # Direct torch.Tensor, no from_dlpack214 ```2154. **For deployment**: Use AOT compilation → export to `.o` → load at runtime216217### Workflow 4: Debugging & Profiling2182191. **Set environment**: `CUTE_DSL_PRINT_IR=1`, `CUTE_DSL_KEEP_PTX=1`2202. **Use `cute.printf()`** for runtime values (not Python `print`)2213. **Inspect generated code**: `compiled.__ptx__`, `compiled.__mlir__`2224. **Profile**: Enable `CUTE_DSL_LINEINFO=1`, use Nsight Compute/Systems2235. **Debug memory**: Run with `compute-sanitizer python script.py`224225## Output Formats226227A typical CuTe DSL kernel project:228229```230kernel_dir/231 kernel.py # @cute.kernel + @cute.jit functions232 test_kernel.py # Correctness test vs PyTorch reference233 bench_kernel.py # Benchmark with cute.compile() setup234```235236**Success indicators:**237- Correctness test passes (`torch.testing.assert_close`)238- Nsight shows vector loads (LDG.128/LDG.256), not scalar loads239- For GEMM: tensor core utilization > 80% in Nsight Compute240241## Companion Script Contract242243Kernel files used with `scripts/verify_kernel.py` and `scripts/benchmark_kernel.py`244must export three names:245246- `kernel_fn(*inputs)` — the CuTe DSL kernel wrapper (calls `cute.compile` + runs kernel)247- `reference_fn(*inputs)` — PyTorch reference implementation (same signature)248- `get_inputs()` — returns a list of CUDA tensors for testing249250```python251# Example kernel.py contract252import torch253import cutlass.cute as cute254from cutlass.cute.runtime import from_dlpack255256def kernel_fn(x):257 out = torch.empty_like(x)258 # ... call compiled cute kernel ...259 return out260261def reference_fn(x):262 return torch.nn.functional.gelu(x)263264def get_inputs():265 return [torch.randn(1024, 512, dtype=torch.float16, device="cuda")]266```267268## Examples269270### Example: 2D Unary Element-wise (ReLU)271272```python273import torch, cutlass, cutlass.cute as cute274from cutlass.cute.runtime import from_dlpack275276@cute.kernel277def relu_kernel(gA: cute.Tensor, gC: cute.Tensor):278 tidx, _, _ = cute.arch.thread_idx()279 bidx, _, _ = cute.arch.block_idx()280 bdim, _, _ = cute.arch.block_dim()281 idx = bidx * bdim + tidx282 m, n = gA.shape[1]283 total = m * n284 if cutlass.dynamic_expr(idx < total):285 a = gA[(None, (idx // n, idx % n))].load()286 gC[(None, (idx // n, idx % n))] = cute.where(a > 0, a, 0)287288@cute.jit289def relu_host(mA: cute.Tensor, mC: cute.Tensor):290 vec = 16 // (mA.element_type.width // 8)291 gA = cute.zipped_divide(mA, (1, vec))292 gC = cute.zipped_divide(mC, (1, vec))293 T = 256294 N = cute.size(gA.shape[1])295 relu_kernel(gA, gC).launch(grid=((N+T-1)//T,1,1), block=(T,1,1))296297x = torch.randn(1024, 512, dtype=torch.float16, device="cuda")298out = torch.empty_like(x)299relu_host(from_dlpack(x, assumed_align=16), from_dlpack(out, assumed_align=16))300```301302## Error Handling303304| Error | Cause | Fix |305|-------|-------|-----|306| `MLIR function requires a Context` | Called @kernel from Python | Launch via @cute.jit host function |307| `DSLAstPreprocessorError` on return | Early return in @kernel | Use `if cutlass.dynamic_expr(cond):` |308| Type mismatch on store | `a * 2` promotes FP16→FP32 | Use `a + a` or `.to(cutlass.Float16)` |309| `could not get source code` | Kernel in `exec()` context | Write to file and import |310| Scalar loads in Nsight | Missing alignment hint | Add `assumed_align=16` to `from_dlpack` |311| `Missing required argument` | Not all @jit params passed | Pass ALL declared parameters |312| `AttributeError: sigmoid` | No `cute.math.sigmoid` | Use `1.0/(1.0+cute.math.exp(-x))` |313314See `references/troubleshooting.md` for the full error table and limitations.315316**Debugging rule:** Never delete kernel.py during debugging. Use `backup_file`317to save a checkpoint, then `edit_file` to iterate. If stuck, `revert_file` to318restore the backup. A partially-working kernel is always better than no kernel.319320## Finding More Information321322### Tier 1: This File (SKILL.md)323324Workflows above cover element-wise kernels, GEMM, framework integration, and325debugging. Search this file first for procedural questions.326327### Tier 2: references/ Directory328329Grep for keywords across `references/`. Headers are grep-friendly.330331| File | Content |332|------|---------|333| `concepts-architecture.md` | Core abstractions, terminology, compilation pipeline |334| `concepts-layouts.md` | Layout algebra: composition, complement, divide, swizzle |335| `concepts-tensors.md` | Tensor types, partitioning, tiling, predication |336| `concepts-mma.md` | MMA atoms, TiledMMA, per-architecture tensor core ops |337| `patterns-getting-started.md` | Installation, decorators, first kernel walkthrough |338| `patterns-elementwise.md` | Invariant principles, pattern variations, reference impl |339| `patterns-gemm.md` | 3-level tiling, shared memory, pipelining, autotuning |340| `patterns-memory.md` | from_dlpack, TMA, cp.async, TMEM, copy atoms |341| `patterns-compilation.md` | Control flow, JIT caching, TVM FFI, AOT compilation |342| `patterns-pipeline.md` | Producer-consumer, pipeline classes, barriers, warp specialization |343| `api-core.md` | cute module: layouts, tensors, math, copy, gemm, printing |344| `api-arch.md` | cute.arch: thread indexing, sync, atomics, memory ops |345| `api-nvgpu.md` | cute.nvgpu: warp/warpgroup/cpasync/tcgen05 MMA and copy |346| `api-runtime-utils.md` | Runtime: from_dlpack, fake tensors, utils, schedulers |347| `troubleshooting.md` | Debugging, env vars, common errors, limitations, FAQ |348349**How to search:** Grep for your keyword across `references/`. Read only the350file and section that Grep points to.351352### Tier 3: Original Documentation353354If Tiers 1–2 don't answer, consult the source:355- **Web**: https://docs.nvidia.com/cutlass/latest/356- **GitHub**: https://github.com/NVIDIA/cutlass357- Fetch specific doc pages or search for "CUTLASS CuTe DSL <topic>"358- Consider distilling the answer back into references/