[No Commit] Cutile experiments - #77
Open
AmesingFlank wants to merge 1 commit into
Open
Conversation
…son sweep Ports every canonical Triton oracle in the corpus to cuTile (cuda.tile), then benchmarks both under the same harness for a compiler-vs-compiler comparison. Coverage: 1717 real cuTile ports (99.4% of 1727 patterns), 10 stubs where numerics diverged past the 1% tolerance. Fairness controls: 240 ports had torch reductions in oracle_forward that Triton kept in-kernel — moved back into @ct.kernel. 150 top-loss ports had code-quality antipatterns (.contiguous() on already-contig views, torch pad copies, tiny BLOCK sizes) — fixed to remove them. After both waves, cuTile mirrors Triton in kernel count, ct.launch count, and BLOCK sizes. Setup: 2× B200, bench_parallel --oracles, 10 warmup / 40 rep / 5 rounds min-of-N, CUDA-graph capture, exclusive per-GPU flock. Headline (merged coverage: 2077 comparable dir×shape points): median cuTile / Triton = 1.11× (11% slower on the typical kernel) geomean cuTile / Triton = 1.71× (long tail of hard cases) cuTile faster than Triton: 225 (11%) Triton faster than cuTile: 1800 (87%) cuTile beats torch.compile: 33% (vs Triton's 79%) Files added: repros_cutile/canonical/<name>/oracle.py — 1727 cuTile ports (10 stubs) cutile_results/ — sweep JSONs + summary.md scripts/CUTILE_*.md — porting/fairness instructions scripts/cutile_reference.md — Triton→cuTile cheat sheet scripts/compare_triton_vs_cutile.py — comparison tool scripts/select_working_cutile_dirs.py — port audit tool scripts/validate_cutile_oracle.py — per-oracle numerics validator scripts/merge_and_compare.py — merge multiple sweeps scripts/cutile_batches/ — worklists used by port subagents See cutile_results/summary.md for the full analysis. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
cuTile vs Triton — Compiler Comparison Results
What this is
The
better-benchmarkcorpus ships each canonical kernel pattern with aTriton oracle (a hand-written reference kernel that serves as the
optimization target for
torch.compile's output). This experiment adds acuTile port for every one of those patterns and benchmarks both against
torch.compilewith the same harness, so the two GPU DSLs can be comparedhead-to-head on the same workload.
The goal is a compiler-vs-compiler comparison: Triton's compiler vs
NVIDIA's cuTile compiler. Both ports do the same computation with the same
kernel structure — differences in wall time reflect codegen quality, not
port quality.
Corpus coverage
@ct.kerneldoing substantive work; the numerics gate passed against the eager
Repro. Ports live underrepros_cutile/canonical/<name>/oracle.py.cuTile numerics diverged past the 1% tolerance (e.g. PyHPC Thomas
solver, a 30-kernel serial stencil).
Fairness discipline
The point of the comparison is compiler codegen quality, not port skill.
Two rounds of audits were applied to eliminate unfair advantages / handicaps:
240 cuTile ports had torch reductions / erf / softmax in
oracle_forwardwhile the corresponding Triton oracle kept thoseinside its kernel body — these were rewritten to compute in-kernel
via
ct.sum/ct.exp/ an Abramowitz-Stegun erf polynomial.150 top-loss cuTile ports had code-quality antipatterns — mostly
unnecessary
.contiguous()calls on views that were alreadycontiguous,
torch.zeros(padded); pad[:H,:W] = srcstyle pad-copiesthat could have been expressed with
padding_mode=ct.PaddingMode.ZERO,and tiny BLOCK sizes (
BLOCK=1or4) when Triton usedBLOCK=1024. These were rewritten to remove the antipattern whilepreserving the Triton kernel structure exactly.
After these fixes cuTile mirrors Triton in number of kernels, number of
ct.launchcalls, and BLOCK sizes wherever the numerics gate allows.Setup
scripts/bench_parallel.py --oracles--n-warmup 10 --n-rep 40 --rounds 5, min-of-N across rounds,each run inside an exclusive GPU flock so per-GPU timing is isolated
from cross-process interference.
torch.compilecompiles the eagerReprofor thesame shape, then CUDA-graph-captures both compile-output and the
oracle. Times are captured graph-replay times.
triton_787dirs_all_shapes.json+cutile_787dirs_all_shapes_post_fix.json:every shape point in the first-wave 787-dir subset. This gives
per-shape resolution for the well-covered subset.
triton_1717dirs_first_shape.json+cutile_1717dirs_first_shape.json:one representative shape per canonical dir across the full 1717-dir
corpus. This gives broad coverage of the long tail.
triton_merged.json+cutile_merged.json: the union.Headline (merged coverage — 2077 comparable points)
Read: on the median kernel, cuTile is 11% slower than Triton. On the
geomean, cuTile is 71% slower — the gap between median and geomean is
the long tail of hard cases (see below).
torch.compilefloor comparisonEach oracle is graded against
torch.compile's output for the sameRepro:Triton lands at or above the
torch.compilefloor 79% of the time.cuTile lands there 33% of the time.
Top 10 kernels where cuTile beats Triton
Simple pointwise and single-axis reductions.
Top 10 kernels where cuTile loses hardest
Analysis
1. cuTile is competitive on simple pointwise / single-axis reductions
The median case (1.11× slower) and the top wins both suggest cuTile's
compiler produces near-Triton-quality code for straightforward pointwise
kernels and single-axis reductions. Both compilers seem to lower these
patterns effectively; the small deltas are probably launch overhead and
register-pressure differences.
2. The long tail is not code quality — it's cuTile compiler weakness on specific patterns
Every top-loss kernel was audited (and re-audited) for antipatterns.
None of the 20 worst losses have unfair torch offloading,
.contiguous()copies, or tiny BLOCK sizes. The cuTile ports look structurally identical
to the Triton ports — but they run 30-400× slower. This is a genuine
codegen gap.
Concrete failure modes observed:
Cooperative split-K reductions with multiple outputs (e.g.
sum_sum_sum_127fc8edd5da,sum_sum_sum_65c3d9f36fd9). Triton's split-Kreduces to launching one kernel per split with per-CTA reductions and
then a finalizer that sums per-CTA partials. cuTile ports that mirror
this structure run drastically slower — likely because cuTile's
cross-CTA reduction primitives don't map to the same warp-shuffle
strategy Triton uses.
Channels-last non-power-of-2 reductions (e.g.
var_mean_c003cf6c87f4,var_mean_e98d6d833b6e). Triton'smask-based tail handling producescompact PTX; cuTile's
PaddingMode.ZEROon non-pow-2 loads seems toblock coalescing or vectorization on the tail.
Very-small-work kernels launched over huge grids (e.g.
pointwise_b43af69d4124, which processes 4-element blocks 5.9M times).Triton compiles these to trivially small kernels with high grid
occupancy. cuTile's overhead per program appears to dominate here.
Multi-input residual chains (
sum_sum_sum_cb474de4ede0,sum_sum_sum_4ce9013c6e0d). Triton fuses ~20 pointwise ops that writeto shared row-reductions in one kernel; cuTile's fused version of the
same structure runs 30-100× slower even though the kernel body is
identical shape to Triton's.
3. cuTile beats
torch.compilefar less than Triton doesTriton oracles beat/match
torch.compileon 79% of kernels; cuTileoracles do the same on 33%. Because
torch.compileitself producesTriton (via TorchInductor), Triton is playing at home. But 33% is much
lower than one would expect from "another optimizing GPU compiler on the
same problems" — suggesting cuTile's compiler still has meaningful room
to close on optimization patterns TorchInductor already generates well.
4. Fairness controls affected the numbers materially
Before the fairness+perf-fix waves, the same 787-dir subset showed
geomean 2.10× / median 1.17×. After fixes:
geomean 1.71× / median 1.11×. The gap tightened by ~40% in geomean
(a lot of it was avoidable
.contiguous()copies and torch offloads).But it did not close on the top losses — those really are cuTile
compiler codegen issues.
What's next
PaddingMode.ZEROtail handling on non-pow-2 loads(bf16 accumulation ordering,
prims.fmavs separate mul+add) — couldbe revisited if
torch.allclose(atol=1e-2, rtol=1e-2)is relaxed forthe specific bit-level-sensitive patterns.
Files in this directory
summary.mdtriton_merged.jsoncutile_merged.jsoncomparison_merged.jsoncomparison_merged.csvtriton_787dirs_all_shapes.jsoncutile_787dirs_all_shapes_post_fix.jsontriton_1717dirs_first_shape.jsoncutile_1717dirs_first_shape.jsoncomparison_pre_fix_787.json