Skip to content

Leaves-first order for large power-of-two transforms - #5

Open
pankgeorg wants to merge 6 commits into
integration/allfrom
exp/large-n-leaves
Open

Leaves-first order for large power-of-two transforms#5
pankgeorg wants to merge 6 commits into
integration/allfrom
exp/large-n-leaves

Conversation

@pankgeorg

@pankgeorg pankgeorg commented Aug 30, 2026

Copy link
Copy Markdown
Member

Stacked on #3 (the diff includes the SIMD pass). Above 2^18 elements the depth-first recursion reads each 64-point leaf at a stride that uses one element per cache line (2.2–3.8× penalty at 2^18–2^22, benchmark/KERNEL_STAGES.md). src/leaffirst.jl: compute the 4096/2048-point sub-transforms first in input order, gathering one cache line of pencils at a time into a plan-owned buffer, then the remaining butterfly passes level by level; same operations, identical output.
compare3 vs integration/all, aarch64 Neoverse-N1, 1 thread, 505 cases (with #3): 1.21× geomean; ComplexF64 fft 2^18 6.4→4.1 ms, 2^20 44.5→21.1 ms, 2^22 193→103 ms = FFTW MEASURE's 20.8 / 102.2 ms (ESTIMATE 52.7 / 238 ms); pow2 class 1.30× (ComplexF64 now 0.94× of FFTW ESTIMATE), ComplexF32 pow2 1.54×, primes/awkward 1.2–1.5× (Bluestein's padded transforms). Table: benchmark/compare3/aarch64/large/COMPARE3.md on bench/compare3.
Tested: full suite green on 4 threads; new test/leaffirst.jl (2^18–2^21, both parities of log2 n, complex/real/backward, zero allocation) — added after an rfft of 2^20 exposed a wrong digit reversal for odd log2 n.
x86-64 (companion session, benchmark/x86-64/compare3/leaves/): 1.25× geomean; pow2 1.25× ComplexF64 / 1.68× ComplexF32; primes 1.19× / 1.64× (Float32 primes reach parity with FFTW ESTIMATE, 1.01×).

W butterflies per iteration on SIMD.jl vectors (2 for ComplexF64, 4 for
ComplexF32); the twiddle table keeps its compact layout and the triplets
are rearranged in registers. Falls back to the scalar loop for strided or
non-contiguous output and for other element types.
Above 2^18 elements the depth-first recursion reads each leaf at a stride
that uses one element per cache line. Compute the 4096-point
sub-transforms first, in input order, gathering one cache line of pencils
at a time into a plan-owned buffer, then run the remaining butterfly
passes level by level. Same operations, identical output; 2^20 43 -> 21 ms,
2^22 188 -> 101 ms (ComplexF64, Neoverse-N1, with the SIMD pass).
…of two), test for 2^18-2^21

N/B must be a power of 4; with a fixed B = 4096 that failed for odd log2 N
(e.g. the 2^19 complex transform inside a 2^20 rfft) and the digit reversal
wrote out of bounds.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant