Repository navigation
Conversation
Computes `C = β * C + α * permutedims(A, p)`, as used by TensorOperations. Arrays that fit in a single block skip the layout planning, blocking and threading machinery: the dimensions are ordered by the strides of the destination, fused, and passed to the kernel directly. A nonzero `β` is handled in the same pass instead of a separate reduction kernel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lkdvos
marked this pull request as draft
October 29, 2026 21:09
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.
Builds on #98 (and #97). It only uses #98 to avoid looping over the padded singleton dimensions, and can be rebased onto #97 if #98 is dropped.
This adds
permutedims!(C::StridedView, A::StridedView, p, α, β), computingC = β * C + α * permutedims(A, p)without readingCifβis zero. This is the operation behind everytensoradd!in TensorOperations, which currently goes through_mapreducedim!with a permuted view, and with a separate reduction kernel andinitoppass forβ ≠ 0.CandAtogether fit in one block, both in CPU memory): the dimensions are ordered by the strides ofC, fused, and passed to the kernel directly. This skips constructing the permuted view,promoteshape, the stride ranking, the blocking and the threading check. A nonzeroβis handled in the same pass, as a map over(C, C, A).β ≠ 0was 5–10% slower than the reduction kernel there.The 3-argument
permutedims!is unchanged.Benchmarks
p = (1, 4, 2, 5, 3, 6), single-threaded, ns. "TO-style" is the current TensorOperations call through_mapreducedim!on this branch.permutedims!permutedims!The arrays from 4096 elements on take the general path, so the differences there are noise. For 4 elements, the remaining ~70 ns are mostly setup: checking the permutation (~8 ns) and the sizes (~6 ns), sorting (~9 ns) and fusing (~25 ns) the dimensions; the kernel itself takes ~20 ns.
I also tried a dedicated non-generated kernel for the small path, with an odometer over the outer dimensions. It halves the compile time of the small path, but is 2–4× slower from 64 elements on, because the innermost runs are short for these permutations.
Tests
There is a new testset covering ranks 1 to 6, real and complex element types, strided and conjugated views,
β = 0withNaNinC, the general path and the error paths. The GPU tests check that JLArray-backed views take the general path. The full test suite passes, single- and multi-threaded (4 threads).A follow-up in TensorOperations can then call this method from
stridedtensoradd!.🤖 Generated with Claude Code