Conversation
…r tiling write what it owns Claude-Session: https://claude.ai/code/session_01AUTdnWQ8FGUP5FKR7dJsKs
|
Preview available at https://floneum.github.io/kalosm/pr-preview/pr-459/ |
…nning matrix-matrix products Claude-Session: https://claude.ai/code/session_01AUTdnWQ8FGUP5FKR7dJsKs
…knowing the families Claude-Session: https://claude.ai/code/session_01AUTdnWQ8FGUP5FKR7dJsKs
…inding has not moved Claude-Session: https://claude.ai/code/session_01AUTdnWQ8FGUP5FKR7dJsKs
…ove its indices in range A fold's work did not mention its lane group, so every reduction strategy priced the same and the choice fell to a seed order that led with the widest. A 40-element reduction ran on 256 lanes where 2 measured eleven times faster. Charging the slots a strategy issues, and seeding by the narrowest group that still fills the device, picks what the hardware measures. Alongside: the tuner refused to race any plan holding an in-place launch, when what it needs is repeatability -- a Set scatter re-runs to the same bytes, and padding, cat, stack and slice_assign are all Set scatters, so no convolution could ever have a schedule measured. And the sampler took two points off a schedule domain, so three of an elementwise map's four tilings were never timed. A split-K coop point is now illegal rather than merely unbuildable: no emitter combines the partials, and a cost change was enough to make one win. conv1d 12.0x slower than burn -> 2.3x; batched matmul 2.4x slower -> 2.7x faster. 746 conformance results, 0 failed, 0 miscompiles.
Opening a command encoder, closing it and submitting cost 6.4 us of host time between them in a browser, where every call crosses the wasm boundary. Paid once per resolve against kernels that often run in less, it was most of what a small dispatch cost: 19 us of a 20 us host path, measured per phase in the page itself. Work is now recorded into an encoder that stays open, and submitted when something needs the results -- a wait, a readback, a timestamp read, an upload that would otherwise jump the queue, or 32 dispatches, whichever comes first. Nothing observes the difference: submissions run in order, so a dispatch recorded later still sees an earlier one's writes, which is the same guarantee the buffer pool already recycles on. A timed resolve keeps its own submission, so the tuner still measures what it thinks it measures. Six elementwise cases went from 1.7-2.3x slower than burn to parity or ahead; decode-shaped kernels gained too (q4k gemv 7.7x -> 10.8x faster, rope 3.5x -> 5.6x). 746 conformance results, 0 failed, 0 miscompiles.
wasm requests neither cooperative matrices nor subgroups, so a native run exercises schedules the page never sees -- which is how a matrix-vector kernel winning a matrix-matrix product stayed hidden. FUSOR_NO_COOP already dropped the first; FUSOR_NO_SUBGROUP drops the second, and together they reproduce what a page runs.
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.
Stacked on #458, which is what made the benchmark numbers trustworthy enough to chase. It is based on that branch, so the two commits from #458 ride along here until it merges; the new work is the last commit,
cb0bb6269. One kernel gap closed, two correctness bugs fixed on the way, and the rest of the losses measured rather than guessed at.An elementwise map had no schedule to choose from
lower_floor::lower_mapminted everyLaunch::MapwithScheduleDomain::Point, a domain with no alternatives in it. Nothing for the extractor to choose between and nothing the tuner could race, so every elementwise kernel on the GPU ran one output per thread, forever. The tuner said so when asked: "not raced: no launch of 1 offers a variant above 0 macs".fusor_tile::rulesalready explains the intended shape of the fix, in a comment on why there is deliberately noTILE_MAPrule: aMapdomain minted as an additive alternative regresses extraction, so it has to be attached where the node is minted. It now is.The cost model picks
tm = 4unprompted, and racing the domain confirms that is the right call: 28.5 us untiled against 19.5 us tiled, and no other offered tiling beats it.The linear tiling wrote a quarter of its output
Attaching the domain exposed a miscompile that had been sitting behind it.
tiled_griddivides the dispatch bytm, so a thread ownstmelements, but thedim: Nonearm oflower_kmapwrote exactly one and left the rest of the output untouched. The member sweep caught 20 of them the moment the tilings became selectable, every one readingincumbent -1.82 vs 0.The arm now walks its
tmelements, taking them a grid apart rather than consecutively so the threads of a workgroup stay on consecutive elements and the accesses keep coalescing.This was reachable before this branch:
fusion::linear_domain_ofhands composites the sameMapDomain::linear, whose entries are alldim: None.The member sweep called f16 rounding a miscompile
agreescompared bit patterns for every dtype except f32, so two members of a class that evaluate the same expression through different intermediates were reported as computing wrong values whenever the result was half precision.dtypes::arithmetic_in_every_float_dtypetripped it.Integers still have to match exactly. Floats are compared to the precision they carry, f16 and bf16 through a wider relative bound than f32 because half precision holds about three decimal digits.
Conformance: 746 results, 737 passed, 9 skipped, 0 failed, 0 miscompiles under the member sweep.
What is still slow, and why
Measured, not guessed. Per-kernel spans are from
FUSOR_TIME_RANGE, host cost fromFUSOR_RESOLVE_PROFILE.conv1d, 14x behind burn. Four dispatches:
scatter_dense96 us,kmap12 us,kfold97 us,kmap11 us, for a convolution of 645 kFLOP. Two causes, both structural. The zero padding is materialized as aScatter{Set}into a zeros leaf, which is 45% of the time and writes 33 KB at about 0.34 GB/s. And because that scatter is in place, the whole plan is disqualified from tuning —"not raced: the plan has an in-place launch"— so nothing ever corrects the second cause: the contraction's fold dispatchesgrid=[16384,1,1], a whole workgroup per output element to reduce 40 values.A k-aware move-ordering seed for fold strategies was tried and reverted: it left conv's fold at 96.5 us, so the selection is the cost model's rather than the seed's, and shipping an inert reordering that perturbs every other fold is not worth it.
The cheap cases are dispatch-bound in the browser, not kernel-bound. Their browser times cluster at 0.033 to 0.044 ms whatever the workload: a 50k-element rank-4 multiply costs 0.033 and a 262k-element add costs 0.044. A resolve on a replay hit with one launch costs about 35 us of host time natively, which is why the kernel win above does not show up on the page. Closing that gap is host-path work, not kernel work.
Attention and dense matmul, around 2x.
attention_causal_smallspends 115 us in onesgemm;dense_matmul_squareruns a 256-cubecoop_matmulat 62 us, about 540 GFLOP/s.https://claude.ai/code/session_01AUTdnWQ8FGUP5FKR7dJsKs