Debug Distributed Hang
sgl-project/sglang
Debug hanging issues in SGLang distributed inference (TP/PP/DP/EP).
Author Triton kernels with automatic warp specialization (AutoWS).
$ npx skills add facebookexperimental/triton --skill autows-authoring -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install facebookexperimental/triton autows-authoring --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/facebookexperimental/triton.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/autows-authoring .claude/skills/autows-authoring && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "autows-authoring" agent skill from https://github.com/facebookexperimental/triton/tree/main/.claude/skills/autows-authoring into .claude/skills/autows-authoring/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "autows-authoring", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/facebookexperimental/triton/tree/main/.claude/skills/autows-authoringType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add facebookexperimental/triton --skill autows-authoring -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install facebookexperimental/triton autows-authoring --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/facebookexperimental/triton.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/autows-authoring .agents/skills/autows-authoring && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "autows-authoring" agent skill from https://github.com/facebookexperimental/triton/tree/main/.claude/skills/autows-authoring into .agents/skills/autows-authoring/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "autows-authoring", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add facebookexperimental/triton --skill autows-authoring -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install facebookexperimental/triton autows-authoring --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/facebookexperimental/triton.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/autows-authoring .cursor/skills/autows-authoring && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "autows-authoring" agent skill from https://github.com/facebookexperimental/triton/tree/main/.claude/skills/autows-authoring into .cursor/skills/autows-authoring/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "autows-authoring", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/facebookexperimental/triton.git --path .claude/skills/autows-authoring--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add facebookexperimental/triton --skill autows-authoring -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install facebookexperimental/triton autows-authoring --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/facebookexperimental/triton.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/autows-authoring .gemini/skills/autows-authoring && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "autows-authoring" agent skill from https://github.com/facebookexperimental/triton/tree/main/.claude/skills/autows-authoring into .gemini/skills/autows-authoring/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "autows-authoring", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install facebookexperimental/triton autows-authoringInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add facebookexperimental/triton --skill autows-authoring -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/facebookexperimental/triton.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/autows-authoring .github/skills/autows-authoring && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "autows-authoring" agent skill from https://github.com/facebookexperimental/triton/tree/main/.claude/skills/autows-authoring into .github/skills/autows-authoring/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "autows-authoring", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add facebookexperimental/triton --skill autows-authoring -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install facebookexperimental/triton autows-authoring --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/facebookexperimental/triton.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/autows-authoring .opencode/skills/autows-authoring && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "autows-authoring" agent skill from https://github.com/facebookexperimental/triton/tree/main/.claude/skills/autows-authoring into .opencode/skills/autows-authoring/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "autows-authoring", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
autows-authoringAuthor Triton kernels with automatic warp specialization (AutoWS).
Autows Authoring is an agent skill from facebookexperimental/triton, published by the product's own GitHub organization. Author Triton kernels with automatic warp specialization (AutoWS). Use when writing new AutoWS kernels, adding warpspecialize=True to tl.range loops, choosing tl.range kwargs and JIT options, debugging why WS was not applied, or structuring a kernel to work with both Meta WS and upstream OAI Triton. Covers GEMM and Flash Attention patterns on Hopper and Blackwell.
Its SKILL.md is about 7.1k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Development, covering GPU and accelerator computing. The repository describes itself as: Github mirror of trition-lang/triton repo. The licence is MIT.
3 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 6f3dd70. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
pythonFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Autows Authoring loads about 7.1k tokens when it runs. Until then it costs about 96 tokens; SKILL.md has 2,177 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from facebookexperimental/triton at commit 6f3dd70, republished under its MIT licence (© facebookexperimental). 2,177 words, ~7,094 tokens.
.claude/skills/autows-authoring/SKILL.md (or your agent's skills folder).AutoWS is Meta's compiler-driven warp specialization for Triton kernels. Instead
of manually writing producer/consumer partitions with TLX primitives (barriers,
tlx.async_tasks, local_alloc), you annotate tl.range() with
warp_specialize=True and the compiler automatically partitions ops, inserts
barriers, allocates SMEM/TMEM buffers, and handles multi-buffering.
Minimal recipe:
TRITON_USE_META_WS=1 (or triton.knobs.nvidia.use_meta_ws = True)tl.range(..., warp_specialize=True) on your loopnum_warps >= 4 at launchRelated skills: autows-testing (run tests), ir-debugging (IR dumps),
autows-docs (compiler internals).
Place warp_specialize=True on the outermost/persistent loop. For
persistent kernels, annotate the tile loop
(tl.range(start_pid, num_tiles, NUM_SMS, warp_specialize=True)), not the
inner K-reduction loop. The inner loop uses plain range(). For
non-persistent kernels, annotate the main compute loop.
Use TMA loads. AutoWS partitions loads into a producer warp group and
compute into consumer warp groups. This partitioning is most effective with
TMA descriptor loads (a_desc.load(...)) rather than pointer-based
tl.load(). TMA enables async bulk copies that the producer can issue
independently while consumers compute. All reference kernels use
TensorDescriptor + desc.load()/desc.store().
Memory allocation and partition scheduling kwargs are Meta-only. The
tl.range() kwargs for controlling memory allocation (smem_alloc_algo,
tmem_alloc_algo, smem_budget, smem_circular_reuse) and partition
scheduling (merge_epilogue, merge_correction,
merge_epilogue_to_computation, separate_epilogue_store) are consumed
exclusively by Meta's WS passes. They do not exist in OSS Triton's
tl.range() — see OSS Fallback for how to gate them.
Compute the post-loop epilogue from the genuine MMA accumulator — never a
synthetic matmul. The partition scheduler keeps a post-loop
reduction/gate/epilogue only if it sits in a real MMA's backward slice. If the
reduction is fed by a synthetic matmul inserted only to create an MMA (e.g.
(x·x)@e0 to get a row-sum), the post-loop region belongs to no genuine MMA
and the scheduler elides the entire epilogue: the kernel still emits
ttg.warp_specialize and passes a structural WS check, but the tl.sum /
normalize / tt.store ops are all dropped and the output is unwritten garbage
(a silent correctness failure, not a compile error). Reduce or gate from the
real A@B accumulator instead. Confirm the WS TTGIR has a dedicated
"epilogue" Meta partition and that the store ops survive.
Environment variable (recommended for running kernels from the command line):
TRITON_USE_META_WS=1 python my_kernel.pyAlso add TRITON_USE_META_WS=1 to the kernel script's module docstring so
users know it's required:
"""
My AutoWS GEMM kernel.
Usage:
TRITON_USE_META_WS=1 python my_gemm.py
"""Programmatic (recommended for correctness tests only):
with triton.knobs.nvidia.scope():
triton.knobs.nvidia.use_meta_ws = True
# ... launch kernel ...Use triton.knobs.nvidia.scope() in correctness tests so the knob is
automatically restored after the test, preventing state leakage between test
cases. Do NOT use scope() for actual runtime/benchmark scripts — use the
TRITON_USE_META_WS=1 env var instead.
TRITON_USE_META_WS is a cache-invalidating env var (listed in
include/triton/Tools/Sys/GetEnv.hpp), meaning changing it forces
recompilation.
| Env Var | Default | Purpose |
|---|---|---|
TRITON_USE_META_WS | False | Master switch for Meta WS vs upstream OAI WS |
TRITON_DISABLE_WSBARRIER_REORDER | False | Disable WS barrier reordering |
TRITON_ENABLE_INTERLEAVE_TMEM | True | Interleave TMEM pass (Blackwell) |
Source: python/triton/knobs.py lines 502-534
tl.range() Kwargs ReferenceDefined in python/triton/language/core.py (tl.range.__init__).
| Kwarg | Type | Default | Description |
|---|---|---|---|
warp_specialize | bool | False | Enable AutoWS on this loop |
flatten | bool | False | Loop flattening for persistent kernels. WARNING: flatten=True currently does NOT warp-specialize — the kernel runs but skips WS |
data_partition_factor | int/None | None | Split work across N data partitions. None/1 = no split, 2 = splits BLOCK_M in half. Requires sufficient BLOCK_SIZE_M (256 for Blackwell dp=2, 128 for Hopper dp=2) |
These kwargs control how the compiler allocates SMEM/TMEM buffers. They are
consumed by WSMemoryPlanner.cpp via loop attributes.
| Kwarg | Type | Default | Description |
|---|---|---|---|
smem_alloc_algo | int/None | None | SMEM allocation strategy (0 or 1). Strategy 1 is preferred for FA kernels |
tmem_alloc_algo | int/None | None | TMEM allocation strategy (Blackwell only) |
smem_budget | int/None | None | Override SMEM budget in bytes |
smem_circular_reuse | bool/None | None | Enable circular reuse of SMEM buffers |
These kwargs control how PartitionSchedulingMeta assigns ops to partitions.
They override pass-level defaults (all false) via per-loop attributes, read at
PartitionSchedulingMeta.cpp lines 2614-2629.
| Kwarg | Type | Default | Description |
|---|---|---|---|
merge_epilogue | bool | False | Merge epilogue ops into the computation/correction/reduction partition |
merge_correction | bool | False | Merge softmax correction ops into the computation partition |
merge_epilogue_to_computation | bool | False | Merge epilogue ops directly to the computation partition |
separate_epilogue_store | bool | False | Separate epilogue store ops into their own 1-warp partition |
Passed at kernel launch time. Defined in CUDAOptions at
third_party/nvidia/backend/compiler.py lines 145-180.
| Option | Type | Default | Description |
|---|---|---|---|
num_warps | int | 4 | Total warps. Must be >= 4 and power of 2 for WS |
num_stages | int | 3 | Pipeline depth / multi-buffer count |
minRegAutoWS | int | 24 | Min registers for non-tensor partitions. Divisible by 8 |
maxRegAutoWS | int/None | None | Max registers for tensor partitions. Divisible by 8 |
pingpongAutoWS | bool | False | Enable ping-pong barriers between two consumer partitions |
early_tma_store_lowering | bool | False | Lower TMA stores before partition scheduling |
minRegAutoWS / maxRegAutoWS)These control how the 64K hardware register file is divided across
warp-specialized partitions. Each partition runs a subset of warps and can have
a different register cap (emitted as PTX setmaxnreg instructions).
Partition types:
minRegAutoWS registers.maxRegAutoWS registers (if set) or split the remainder
evenly (if not set).When maxRegAutoWS is NOT set (default):
Non-tensor partitions get minRegAutoWS (24). Tensor partitions AND the default
partition all receive sentinel value -1, meaning "split the remaining register
pool evenly after deducting the fixed allocations":
regsPerThread = (totalRegs - fixedRegs) / leftoverThreadsComputed in AllocateWarpGroups.cpp lines 244-280.
When maxRegAutoWS IS set:
Non-tensor partitions get minRegAutoWS. Tensor partitions get maxRegAutoWS.
The default partition gets ALL leftover registers.
Computed in OptimizePartitionWarps.cpp lines 295-314.
Both values must be divisible by 8 (compiler.py:140-142).
To see which partitions map to which register budget and verify the actual allocation:
IR inspection: Set MLIR_ENABLE_DUMP=1. Look for the
ttg.warp_specialize op which carries:
requestedRegisters = array<i32: ...> — what OptimizePartitionWarps requestedactualRegisters = array<i32: ...> — what AllocateWarpGroups computed[default_partition, partition_0, partition_1, ...]-1 in requestedRegisters means "split evenly"requestedRegisters = array<i32: 24, -1, 24> means load partition
gets 24, computation splits leftovers, epilogue store gets 24PTXAS log: TRITON_DUMP_PTXAS_LOG=1 prints ptxas verbose output showing
register usage.
PTX inspection: kernel.asm['ptx'] — search for
setmaxnreg.inc.sync.aligned and setmaxnreg.dec.sync.aligned to see
register reallocation at partition boundaries.
Warp-specialize the inner K-reduction loop. Based on matmul_kernel_tma_ws in
python/test/unit/language/test_tutorial09_warp_specialization.py lines 34-94.
"""
GEMM with AutoWS (K-loop warp specialization).
Usage:
TRITON_USE_META_WS=1 python my_gemm.py
"""
@triton.jit
def matmul_kernel_ws(a_desc, b_desc, c_desc, M, N, K,
BLOCK_SIZE_M: tl.constexpr, BLOCK_SIZE_N: tl.constexpr,
BLOCK_SIZE_K: tl.constexpr,
DATA_PARTITION_FACTOR: tl.constexpr,
SMEM_ALLOC_ALGO: tl.constexpr,
SEPARATE_EPILOGUE_STORE: tl.constexpr, ...):
# ... pid computation ...
accumulator = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32)
for k in tl.range(
k_tiles,
warp_specialize=True,
data_partition_factor=DATA_PARTITION_FACTOR,
smem_alloc_algo=SMEM_ALLOC_ALGO,
separate_epilogue_store=SEPARATE_EPILOGUE_STORE,
):
offs_k = k * BLOCK_SIZE_K
a = a_desc.load([offs_am, offs_k])
b = b_desc.load([offs_bn, offs_k])
accumulator = tl.dot(a, b.T, accumulator)
c_desc.store([offs_cm, offs_cn], accumulator.to(dtype))Warp-specialize the outer persistent loop. Inner K-loop uses plain range().
Based on matmul_kernel_tma_persistent_ws in same file, lines 102-167.
"""
Persistent GEMM with AutoWS (tile-loop warp specialization).
Usage:
TRITON_USE_META_WS=1 python my_persistent_gemm.py
"""
@triton.jit
def matmul_persistent_ws(a_desc, b_desc, c_desc, M, N, K,
BLOCK_SIZE_M: tl.constexpr, BLOCK_SIZE_N: tl.constexpr,
BLOCK_SIZE_K: tl.constexpr, NUM_SMS: tl.constexpr,
DATA_PARTITION_FACTOR: tl.constexpr,
SMEM_ALLOC_ALGO: tl.constexpr,
SEPARATE_EPILOGUE_STORE: tl.constexpr, ...):
start_pid = tl.program_id(axis=0)
num_tiles = tl.cdiv(M, BLOCK_SIZE_M) * tl.cdiv(N, BLOCK_SIZE_N)
k_tiles = tl.cdiv(K, BLOCK_SIZE_K)
for tile_id in tl.range(
start_pid, num_tiles, NUM_SMS,
warp_specialize=True, # on the OUTER loop
data_partition_factor=DATA_PARTITION_FACTOR,
smem_alloc_algo=SMEM_ALLOC_ALGO,
separate_epilogue_store=SEPARATE_EPILOGUE_STORE,
):
# ... compute pid_m, pid_n from tile_id ...
accumulator = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32)
for ki in range(k_tiles): # plain range()
a = a_desc.load([offs_am, ki * BLOCK_SIZE_K])
b = b_desc.load([offs_bn, ki * BLOCK_SIZE_K])
accumulator = tl.dot(a, b.T, accumulator)
c_desc.store([offs_am, offs_bn], accumulator.to(dtype))Warp-specialize the KV-iteration loop with partition scheduling hints.
Based on python/tutorials/fused-attention-ws-device-tma-hopper-or-blackwell.py
lines 150-155.
for start_n in tl.range(
lo, hi, BLOCK_N,
warp_specialize=warp_specialize,
merge_epilogue=True,
merge_correction=True,
smem_alloc_algo=1,
data_partition_factor=DP_FACTOR,
):
# TMA descriptor loads for K and V
k = k_desc.load([start_n, offs_k])
v = v_desc.load([start_n, offs_d])
# QK dot product
qk = tl.dot(q, k)
# ... softmax ...
# PV dot product
acc = tl.dot(p.to(dtype), v, acc)Correctness tests should use triton.knobs.nvidia.use_meta_ws = True (not the
env var) inside a scope() block to avoid state leakage between test cases.
Based on test_tutorial09_matmul_tma_warp_specialize in
python/test/unit/language/test_tutorial09_warp_specialization.py lines 416-492.
import torch
import triton
from triton.tools.tensor_descriptor import TensorDescriptor
def test_my_kernel():
with triton.knobs.nvidia.scope():
triton.knobs.nvidia.use_meta_ws = True
M, N, K = 8192, 8192, 1024
BLOCK_M, BLOCK_N, BLOCK_K = 128, 128, 64
dtype = torch.float16
torch.manual_seed(42)
A = torch.randn((M, K), dtype=dtype, device="cuda")
B = torch.randn((N, K), dtype=dtype, device="cuda")
C = torch.empty((M, N), dtype=dtype, device="cuda")
# TMA requires a custom allocator
def alloc_fn(size, align, stream):
return torch.empty(size, dtype=torch.int8, device="cuda")
triton.set_allocator(alloc_fn)
a_desc = TensorDescriptor(A, A.shape, A.stride(), [BLOCK_M, BLOCK_K])
b_desc = TensorDescriptor(B, B.shape, B.stride(), [BLOCK_N, BLOCK_K])
c_desc = TensorDescriptor(C, C.shape, C.stride(), [BLOCK_M, BLOCK_N])
grid = lambda META: (triton.cdiv(M, META["BLOCK_SIZE_M"])
* triton.cdiv(N, META["BLOCK_SIZE_N"]),)
# Launch — capture handle to inspect IR
kernel = matmul_kernel_ws[grid](
a_desc, b_desc, c_desc, M, N, K,
BLOCK_SIZE_M=BLOCK_M, BLOCK_SIZE_N=BLOCK_N, BLOCK_SIZE_K=BLOCK_K,
DATA_PARTITION_FACTOR=1, SMEM_ALLOC_ALGO=0,
SEPARATE_EPILOGUE_STORE=False,
num_stages=3, num_warps=4,
)
# 1. Verify WS was applied
ttgir = kernel.asm["ttgir"]
assert "ttg.warp_specialize" in ttgir
# 2. Verify correct HW instructions (pick one per arch)
# Blackwell: assert "ttng.tc_gen5_mma" in ttgir
# Hopper: assert "ttng.warp_group_dot" in ttgir
assert "ttng.async_tma_copy_global_to_local" in ttgir
# 3. Compare against reference
ref = torch.matmul(A.float(), B.T.float()).to(dtype)
torch.testing.assert_close(ref, C, atol=0.03, rtol=0.03)IR check: kernel.asm["ttgir"] must contain "ttg.warp_specialize" —
confirms WS was applied.
MMA check: Look for "ttng.tc_gen5_mma" (Blackwell) or
"ttng.warp_group_dot" (Hopper) — confirms tensor core usage.
TMA check: Look for "ttng.async_tma_copy_global_to_local" — confirms
async TMA copies in the producer partition.
Partition check: Set MLIR_ENABLE_DUMP=1 and look for
ttg.partition = array<i32: N> attributes in the IR after
PartitionSchedulingMeta. This shows how ops were assigned to partitions.
Full IR dump: Set TRITON_KERNEL_DUMP=<kernel_name> +
TRITON_ALWAYS_COMPILE=1 to dump IR at each compilation stage. See
ir-debugging skill for details.
AutoWS vs TLX comparison:
TRITON_USE_META_WS=1 python python/tutorials/test_hopper_fwd_autows_vs_tlx.py
ttg.warp_specializeis necessary, not sufficient. Its presence or count alone does not prove a correct WS kernel — an elided epilogue (Key Authoring Rule 5) leaves the op in the IR while the stores are gone. Prefer the named Meta partition list as the reliable signal: a"load"/"gemm"/"computation"set, plus a dedicated"epilogue"partition whenever the kernel has a post-loop epilogue.
2-CTA allows two CTAs in a cluster to cooperatively execute a single MMA, doubling the N dimension of the output tile. This is a Blackwell-only, Meta WS-only feature.
ctas_per_cga=(2, 1, 1) — pass this at kernel launch time (not
cluster_dims or num_ctas). ctas_per_cga is the correct way to enable
2-CTA because it bypasses PlanCTA's unreliable CTASplitNum encoding by
forcing num_ctas=1 internally, then using Transform2CTALoads +
Insert2CTASync for B-operand splitting and cross-CTA synchronization.
two_ctas=True on tl.dot() — tells the compiler this dot product
should use 2-CTA MMA. The compiler automatically splits the B load across
CTAs and inserts cross-CTA barriers.
TRITON_USE_META_WS=1 — 2-CTA with WS is only supported by Meta's WS
pipeline. Upstream OAI WS does not support cluster_dims >= 2.
num_stages=1 — current 2-CTA implementations use 1 pipeline stage.
Grid M dimension must be >= 2 — the grid must launch at least 2 CTAs in
the cluster dimension: grid = (max(triton.cdiv(M, BLOCK_M), 2), ...).
"""
2-CTA GEMM with AutoWS.
Usage:
TRITON_USE_META_WS=1 python my_2cta_gemm.py
"""
@triton.jit
def matmul_2cta_ws_kernel(a_ptr, b_ptr, c_ptr, M, N, K,
stride_am, stride_ak, stride_bk, stride_bn,
stride_cm, stride_cn,
BLOCK_M: tl.constexpr, BLOCK_N: tl.constexpr,
BLOCK_K: tl.constexpr):
pid_m = tl.program_id(0)
pid_n = tl.program_id(1)
offs_am = pid_m * BLOCK_M
offs_bn = pid_n * BLOCK_N
a_desc = tl.make_tensor_descriptor(
a_ptr, shape=[M, K], strides=[stride_am, stride_ak],
block_shape=[BLOCK_M, BLOCK_K])
b_desc = tl.make_tensor_descriptor(
b_ptr, shape=[K, N], strides=[stride_bk, stride_bn],
block_shape=[BLOCK_K, BLOCK_N])
c_desc = tl.make_tensor_descriptor(
c_ptr, shape=[M, N], strides=[stride_cm, stride_cn],
block_shape=[BLOCK_M, BLOCK_N])
accumulator = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32)
k_tiles = tl.cdiv(K, BLOCK_K)
for k in tl.range(0, k_tiles, warp_specialize=True):
offs_k = k * BLOCK_K
a = a_desc.load([offs_am, offs_k])
b = b_desc.load([offs_k, offs_bn])
accumulator = tl.dot(a, b, accumulator, two_ctas=True) # <-- 2-CTA MMA
c_desc.store([offs_am, offs_bn], accumulator.to(tl.float16))grid = (max(triton.cdiv(M, BLOCK_M), 2), triton.cdiv(N, BLOCK_N))
matmul_2cta_ws_kernel[grid](
a, b, c, M, N, K,
a.stride(0), a.stride(1), b.stride(0), b.stride(1),
c.stride(0), c.stride(1),
BLOCK_M=128, BLOCK_N=128, BLOCK_K=64,
num_stages=1,
ctas_per_cga=(2, 1, 1), # <-- enables 2-CTA cluster
)When ctas_per_cga is set with two_ctas=True on tl.dot():
Transform2CTALoads splits the B-operand load: each CTA loads half of
BLOCK_N ([BLOCK_K, BLOCK_N/2]), offset by cluster_cta_id * BLOCK_N/2Insert2CTASync inserts cross-CTA barriers before the 2-CTA MMA using
the "arrive remote, wait local" pattern via mapa instructionsthird_party/tlx/tutorials/blackwell-triton-addmm-2cta_test.pythird_party/tlx/tutorials/blackwell_gemm_2cta.pydocs/design/2cta-autoWS-sync.mdthird_party/nvidia/hopper/lib/Transforms/Transform2CTALoads.cppthird_party/nvidia/hopper/lib/Transforms/Insert2CTASync.cppIf any of these conditions are violated, the compiler silently strips WS annotations and the kernel runs without specialization.
num_warps >= 4 required
(WarpSpecialization.cpp:148-153)scf.if with non-trivial else blocks not supported
(WarpSpecialization.cpp:156-170)PartitionSchedulingMeta.cpp:2664-2698)ScheduleLoops.cpp:40-41)ScheduleLoops.cpp:42-43)ScheduleLoops.cpp:44-47)minRegAutoWS and maxRegAutoWS must be divisible
by 8 (compiler.py:140-142)cluster_dims >= 2 (compiler.py:703-706)flatten=True skips WS — the kernel runs but WS is not applieddata_partition_factor != 1 requires sufficient BLOCK_SIZE_M (256 for
Blackwell dp=2, 128 for Hopper dp=2)The basic tl.range(warp_specialize=True) syntax works with both Meta WS and
upstream OAI WS. The difference is entirely which compiler passes run, controlled
by TRITON_USE_META_WS:
add_warp_specialize; Meta uses
add_partition_scheduling_meta + add_hopper_warpspecadd_hopper_warpspec only (internal
doTaskPartition); Meta runs the full pipelineMeta WS-specific features do NOT work with OSS Triton. The following kwargs
and options are consumed only by Meta's compiler passes. They do not exist in
OSS Triton's tl.range() signature — passing them will cause errors, not silent
no-ops. If the kernel must run on both, use completely separate code paths gated
by tl.constexpr:
merge_epilogue, merge_correction,
merge_epilogue_to_computation, separate_epilogue_storesmem_alloc_algo, tmem_alloc_algo,
smem_budget, smem_circular_reuseminRegAutoWS, maxRegAutoWS, pingpongAutoWSmulti_cta=True and cluster_dims >= 2 with WSearly_tma_store_loweringBecause these kwargs do not exist in OSS Triton's tl.range(), you cannot
conditionally pass them (e.g., smem_alloc_algo=1 if X else None). You must
use completely separate tl.range() calls:
@triton.jit
def _kernel_body(a_desc, b_desc, c_desc, ...):
# ... shared load/dot/store logic ...
@triton.jit
def my_kernel(..., USE_META_WS: tl.constexpr):
if USE_META_WS:
for tile_id in tl.range(
start_pid, num_tiles, NUM_SMS,
warp_specialize=True,
separate_epilogue_store=True,
smem_alloc_algo=1,
merge_epilogue=True,
):
_kernel_body(...)
else:
for tile_id in tl.range(
start_pid, num_tiles, NUM_SMS,
warp_specialize=True,
):
_kernel_body(...)tl.range() kwargs (from python/triton/language/core.py)This is the complete list of every kwarg accepted by tl.range(). Items marked
(Meta only) do not exist in OSS Triton and require separate code paths.
| Kwarg | Type | Default | Available in OSS | Description |
|---|---|---|---|---|
num_stages | int/None | None | Yes | Pipeline depth override at the loop level |
loop_unroll_factor | int/None | None | Yes | Loop unroll factor |
flatten | bool | False | Yes | Loop flattening for persistent kernels. True currently skips WS |
warp_specialize | bool | False | Yes | Enable AutoWS on this loop |
multi_cta | bool | False | Meta only | Enable multi-CTA (2-CTA) mode |
disable_licm | bool | False | Yes | Disable loop-invariant code motion |
data_partition_factor | int/None | None | Meta only | Split work across N data partitions |
disallow_acc_multi_buffer | bool | False | Meta only | Prevent multi-buffering of accumulators |
merge_epilogue | bool | False | Meta only | Merge epilogue into computation/correction/reduction partition |
merge_epilogue_to_computation | bool | False | Meta only | Merge epilogue directly to computation partition |
merge_correction | bool | False | Meta only | Merge softmax correction into computation partition |
separate_epilogue_store | bool | False | Meta only | Separate epilogue store into its own 1-warp partition |
tmem_alloc_algo | int/None | None | Meta only | TMEM allocation strategy (Blackwell only) |
smem_alloc_algo | int/None | None | Meta only | SMEM allocation strategy (0 or 1) |
smem_budget | int/None | None | Meta only | Override SMEM budget in bytes |
smem_circular_reuse | bool/None | None | Meta only | Enable circular reuse of SMEM buffers |
python/triton/knobs.py)| Env Var | Knob | Type | Default | Description |
|---|---|---|---|---|
TRITON_USE_META_WS | knobs.nvidia.use_meta_ws | bool | False | Master switch: Meta WS vs upstream OAI WS |
TRITON_DISABLE_WSBARRIER_REORDER | knobs.nvidia.disable_wsbarrier_reorder | bool | False | Disable WS barrier reordering |
TRITON_ENABLE_INTERLEAVE_TMEM | knobs.nvidia.enable_interleave_tmem | bool | True | Interleave TMEM pass (Blackwell) |
TRITON_DUMP_PTXAS_LOG | knobs.nvidia.dump_ptxas_log | bool | False | Print ptxas verbose output (register usage) |
MLIR_ENABLE_DUMP | — | bool | False | Dump MLIR IR after each pass (for inspecting partitions) |
TRITON_KERNEL_DUMP | — | str | unset | Dump IR at each stage for the named kernel |
TRITON_ALWAYS_COMPILE | knobs.compilation.always_compile | bool | False | Force recompilation (useful with IR dumps) |
CUDAOptions)| Option | Type | Default | Description |
|---|---|---|---|
num_warps | int | 4 | Total warps per CTA. Must be >= 4 and power of 2 for WS |
num_stages | int | 3 | Pipeline depth / multi-buffer count |
minRegAutoWS | int | 24 | Registers for non-tensor partitions. Must be divisible by 8 |
maxRegAutoWS | int/None | None | Registers for tensor partitions. Must be divisible by 8 |
pingpongAutoWS | bool | False | Ping-pong barriers between two consumer partitions |
early_tma_store_lowering | bool | False | Lower TMA stores before partition scheduling |
tl.range definition: python/triton/language/core.py (lines 3454-3484)python/triton/knobs.py (line 516)third_party/nvidia/backend/compiler.py (lines 145-180)third_party/nvidia/backend/compiler.py (lines 659-716)python/test/unit/language/test_tutorial09_warp_specialization.pypython/test/unit/language/test_autows_addmm.pythird_party/tlx/tutorials/testing/test_correctness_autows.pythird_party/tlx/tutorials/fused_attention_ws_device_tma.pythird_party/tlx/tutorials/fused_attention_ws_device_tma_dp.pypython/tutorials/test_hopper_fwd_autows_vs_tlx.pytest/Hopper/WarpSpecialization/© facebookexperimental, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/autows-authoring of facebookexperimental/triton.
Open the folder on GitHubat commit 6f3dd70
Autows Authoring next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Autows Authoring this skillfacebookexperimental/triton | 201 | — | ~7.1k | Automated safety check: Pass | MIT | |
| Debug Distributed Hangsgl-project/sglang | 37k | 2 repos | ~2.4k | Automated safety check: Pass | Apache-2.0 | |
| CUTLASS FMHA Incremental Rebuildmicrosoft/onnxruntime | 22k | — | ~1.3k | Automated safety check: Pass | MIT | |
| Cudatechnillogue/ptx-isa-markdown | 229 | — | ~2.5k | Automated safety check: Pass | None | |
| Fla Triton To Gluonfla-org/flash-linear-attention | 5.8k | — | ~1.6k | Automated safety check: Pass | MIT | |
| Torch Profiler Layer TrackBBuf/AI-Infra-Auto-Driven-SKILLS | 938 | — | ~2k | Automated safety check: Pass | None |
sgl-project/sglang
Debug hanging issues in SGLang distributed inference (TP/PP/DP/EP).
microsoft/onnxruntime
Explains why editing CUTLASS fused-MHA headers in ONNX Runtime can leave stale CUDA kernels after an incremental build, and how to force and verify a real rebuild.
technillogue/ptx-isa-markdown
CUDA kernel development, debugging, and performance optimization for Claude Code.
fla-org/flash-linear-attention
Port an FLA Triton kernel to Gluon when explicit layouts, asynchronous transfers, or scheduling can address a measured bottleneck.
BBuf/AI-Infra-Auto-Driven-SKILLS
Adds verified layer guides such as L0 and L1 and compact GPU lanes to an existing Torch Profiler Chrome trace, changing how it looks but not how it ran.
jaccen/Awesome-Gaussian-Skills
Review 3DGS implementation code for correctness, performance bugs, and best practices.
facebookexperimental/triton
Collect, validate, package, and inspect rocprofv3 Advanced Thread Trace bundles for AMD GPU kernels.
facebookexperimental/triton
Design and run Triton TTGIR debugging ablations using iroverride.
facebookexperimental/triton
Execute the TLX Kernel Optimization Agent CLI on a Triton or TLX kernel.
facebookexperimental/triton
Run NVIDIA compute-sanitizer (memcheck, racecheck, initcheck, synccheck) against a Triton/TLX kernel to find runtime memory and synchronization bugs.
facebookexperimental/triton
Recover from GPU-busy / GPU-unavailable failures. An agent skill from facebookexperimental/triton.
facebookexperimental/triton
Debug Triton compilation by dumping IR at each stage (TTIR, TTGIR, LLVM, PTX).
Categories
Author Triton kernels with automatic warp specialization (AutoWS). Autows Authoring is an agent skill from facebookexperimental/triton, published by the product's own GitHub organization. Author Triton kernels with automatic warp specialization (AutoWS).
Autows Authoring fits situations like: writing new AutoWS kernels; adding warpspecialize=True to tl.range loops; choosing tl.range kwargs and JIT options; debugging why WS was not applied.
Run `npx skills add facebookexperimental/triton --skill autows-authoring -a claude-code`. Or copy the skill folder (.claude/skills/autows-authoring in facebookexperimental/triton) into .claude/skills/autows-authoring in your project. Claude Code loads it when a task matches its description.
Run `npx skills add facebookexperimental/triton --skill autows-authoring -a codex`. Or copy the skill folder (.claude/skills/autows-authoring in facebookexperimental/triton) into .agents/skills/autows-authoring in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add facebookexperimental/triton --skill autows-authoring -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/autows-authoring, .gemini/skills/autows-authoring, .github/skills/autows-authoring and .opencode/skills/autows-authoring in your project.
Going by SKILL.md and its folder, Autows Authoring needs the command-line tools its instructions call (python). Our summary lists: Python 3.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Autows Authoring is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 7.1k tokens (SKILL.md is roughly 28k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Autows Authoring: Debug Distributed Hang (sgl-project/sglang, 37k stars), CUTLASS FMHA Incremental Rebuild (microsoft/onnxruntime, 22k stars), Cuda (technillogue/ptx-isa-markdown, 229 stars) and Fla Triton To Gluon (fla-org/flash-linear-attention, 5.8k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
facebookexperimental (a GitHub organization, an official publisher) maintains it in facebookexperimental/triton, which has 201 GitHub stars. The repository holds 18 skills in this directory. The repository was last updated on October 10, 2026.
Source: facebookexperimental/triton on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.