Repository navigation
One chain form: every smooth length runs on RChain - #30
Conversation
The radix sequence and the stage records of a Stockham chain are data, and the codelets come from the fixed set. The chain type with the radix sequence in its type (Chain, used for smooth lengths up to 128) is removed, with its generated run!/run_lanes!, the 583 compiled chain methods and the dispatch trees from an RChain of a short length into them. Nothing is compiled per length any more. The run-time chain used to cost 9-20 ns more per call. That was not the choice of the codelet at run time (about 1 ns per stage) but the code around it, which the stage loop now avoids: - a line of one stage is one codelet call; - the stage records are one flat vector that carries the twiddle addresses and is read through a raw pointer, so the loop needs no GC frame; - RChain is a mutable struct with const fields, passed as one pointer instead of being copied to the stack of each caller; - the codelet switch is inlined into the loop; - the rows of a plane run inside one call. The addresses in the stage records belong to one chain object. A chain remembers its own address when it is linked and links again when it finds itself elsewhere (a copy, or a plan loaded from a package image, which keeps Ptr values as they were). The tag of the default plans in Bluestein, RealLine and R2RLine is the abstract type TypedKernels. AMD EPYC 9354 (AVX-512), one thread, plan_fft and mul!, 92 cases, 8 rounds in alternating processes, median time over that of the previous code: geometric mean 0.973, 27 cases below 0.95, 8 above 1.05 (short lines of two or three stages, at most 1.13). 1796 methods instead of 2385, package image 61 MB instead of 72 MB, libfftl.so 49.5 MB instead of 55.6 MB. Not verified on aarch64. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
|
Checked on aarch64 (Apple M1 Max, Julia 1.13, one thread,
Same picture as on the EPYC: one-stage lines and small planes gain, a few short One point on the addresses in the stage records: when a plan comes back from an image and several threads call it at once, each of them sees |
slop:
What
Every smooth length now runs on
RChain(radix sequence and stage records as data, codelets from the fixed set). The chain type with the radix sequence in its type (Chain, used for smooth lengths up to 128) is removed, together with@generatedrun!/run_lanes!and the body builders behind them,kernel_methods.jl,small_*_run!) from anRChainof a short length into the compiled chains,Nothing is compiled per length any more.
Why this is possible now
The run-time chain used to cost 9–20 ns more per call, which is why the compiled chain was kept (decision of 2026-11-09). That cost was not the choice of the codelet at run time (about 1 ns per stage) but the code around it:
RChainis a mutable struct withconstfields, passed as one pointer.Measurements
AMD EPYC 9354 (AVX-512), Julia 1.13.3, one thread,
plan_fftandmul!, 92 cases (Float64andFloat32; lines of 2 to 4096, planes of 8 × 8 to 128 × 128, cubes of 8³ to 64³, in-place, backward and real transforms), 8 rounds in alternating processes, median time over the median time onmain:mainFloat32rows of 64)The cases above 1.05 are short lines of two or three stages:
Float3220, 32, 96, 100 (1.09–1.10), 37 rows of 64 (1.13),rfftof 64 (1.07 and 1.09),Float6412 × 7 (1.05). The stage loop runs about 50 instructions per stage around the codelet, without mispredicted branches: 2.4 ns per stage against direct calls of the two kernels ofFloat3232.The machine was shared during the measurement. Over the 8 rounds, the slowest time of
mainover its fastest is 1.04 in the median over the cases, 1.19 at the 90th percentile and 1.55 at most.Size:
mainlibfftl.so(x86-64-v3,--trim=safe)Things to look at
Ptrvalues as they were, so a plan stored in a user's precompiled image would come back with stale twiddle addresses. A chain remembers its own address when its records are linked and links again when it finds itself elsewhere (a copy, a plan loaded from an image). Covered by a test;deepcopyof a plan works after the original is freed.TypedKernels.Chainwas also the tag of the default plans inBluestein,RealLineandR2RLine; the tag is now this abstract type.ChainwithRChaincheck against the direct DFT instead. Quick selection passes with 2 threads (10950 pass, 10 broken as before).libfftlbuilds andfftw3_ctest.shpasses (3940 comparisons, 0 failed).Not done
The decision and its evidence are in
docs/src/explanation/design-decisions.md("One chain form"), the stage loop inimplementation.md.🤖 Generated with Claude Code