VectorFFT is a double-precision FFT library in C for x86 with AVX2 and AVX-512, built for workloads that run many transforms of modest length. It serves complex (c2c), real (r2c, c2r) and real-to-real (DCT, DST, DHT) transforms in 1D, 2D and 3D, in place or out of place, in both complex layouts, interleaved and split, batched and threaded. Its kernels are emitted by its own DAG FFT compiler for each instruction set; the split layout has its AVX-512 kernels today, the interleaved layout's follow from the same compiler. You never pick an algorithm: a call names a contract, the planner races the engines that serve it on your machine, and the winner is kept as wisdom, so the first create measures and every later one replays.
Full performance record — every gauntlet run, multi-threaded scaling, the 2D/3D tiers, accuracy and hardware caveats — is
docs/performance/v1_0_results.md. The runs themselves (csv, calibration logs, banked wisdom) are ingauntlet/results/; this section's record isgauntlet_2_4096_2026-09-23, andgauntlet/is the tool that reproduces it on your own machine.
Platform: Intel Core i9-14900KF (P-core, AVX2), DDR5, GCC 15.2, single thread
Competitor: Intel oneMKL 2025.3 (sequential,mkl_set_num_threads(1))
Contract: 1D complex-to-complex FP64, interleaved, natural order, out of place, K = 1
Cells: every length N from 2 to 4,096 — 4,095 transforms, no size skipped
One line per engine, one point per length, joined in N. Each point is the median of two timing arms with the engine order flipped; every ratio below takes the worse of the two arms, so a win is never an artefact of order. The saw-tooth is the arithmetic of the lengths themselves: powers of two and smooth composites reach 60-77 GFLOPS, primes and rough composites run at 5-10 GFLOPS on both engines, and on those VectorFFT sits above MKL by a steady offset (log scale: equal speed ratios are equal vertical gaps).
| Lengths | Cells | Median speedup | At or above parity | Best |
|---|---|---|---|---|
| 2..16 | 15 | 1.39x | 80% | 2.83x (N=2) |
| 17..64 | 48 | 1.56x | 96% | 4.17x (N=61) |
| 65..256 | 192 | 1.64x | 98% | 7.04x (N=89) |
| 257..1,024 | 768 | 1.40x | 93% | 4.15x (N=508) |
| 1,025..2,048 | 1,024 | 1.27x | 91% | 3.74x (N=1946) |
| 2,049..4,096 | 2,048 | 1.23x | 86% | 4.00x (N=2209) |
| all, 2..4,096 | 4,095 | 1.29x | 89% | 7.04x (N=89) |
| Family | Cells | Median speedup | At or above parity |
|---|---|---|---|
| Powers of two | 12 | 1.13x | 75% |
| Primes | 564 | 1.18x | 89% |
| Other composites | 3,520 | 1.30x | 89% |
Every route is raced per plane by the planner and banked in
wisdom; the design is in
docs/design/il2d_c2c_strategy.md. The record is
gauntlet_2d-pow2grid5.
| Plane size | Cells | Median speedup | At or above parity | Best |
|---|---|---|---|---|
| up to 256 points | 28 | 4.57x | 89% | 10.28x (4x2) |
| 257..4,096 | 38 | 1.55x | 84% | 4.72x (2x256) |
| 4,097..65,536 | 48 | 1.23x | 100% | 2.33x (2x4096) |
| 65,537..4M | 45 | 1.29x | 98% | 1.96x (1024x256) |
| all, 159 planes | 159 | 1.34x | 94% | 10.28x (4x2) |
The same 159 planes at eight threads, MKL at eight threads too. The threaded design is in
docs/design/il2d_c2c_mt.md.
Every volume N1 x N2 x N3 with each side a power of two from 2 to 8,192 and at most 2^22
points: 1,288 transforms, 3D complex-to-complex, interleaved, natural order, out of
place, single thread, against MKL DFTI 3D. One matrix per N1; each cell is the speedup,
worse of the two engine orders, and a cell slower than MKL is outlined. The record is
3d-pow2_2026-09-24.
| Volume | Cells | Median speedup | At or above parity |
|---|---|---|---|
| up to 4,096 points | 220 | 4.54x | 99% |
| 4,097..65,536 | 337 | 1.94x | 99% |
| 65,537..1M | 478 | 1.38x | 98% |
| 1M..4M | 253 | 1.26x | 99% |
| all, 1,288 volumes | 1,288 | 1.55x | 98% |
Every length above 10e-16 is on the flat DIT route, a chain of two large odd radices (2x29x47, 3x29x43, 2x41x43). A tail stage of that route derives most of its twiddle legs from one loaded record instead of loading up to forty-six, and the derived legs carry the loaded value's rounding times their distance from it. That is what makes these lengths fast: the 33 above 10e-16 run at 2.2x MKL's speed at the median and none below 1.2x, the flat route as a whole at 1.7x. The library makes that trade once, for speed, and offers no accuracy modes. A build configuration that takes the loaded form instead may be added later.
A request names a contract: transform, layout, placement, order, length, batch, threads. A cell either has a native engine for it or refuses at create; a dot in the tree is a native engine, a dash a refusal by contract.
- Interleaved and split are two libraries, each with its own engines and wisdom; nothing is converted between them.
- Both placements in each layout, in place and out of place, for the complex transforms; real transforms run in place only under 1D interleaved.
- Order is a contract of c2c: natural by default, scrambled on request, each served by its own writers. Real and trigonometric transforms are natural by construction.
- Any length, 1D to 3D, batches, threads. Every plan is a measured verdict kept in wisdom, never an estimate.
How a plan is chosen: lookup, enumerate, race, argmin, bank. A hit replays the banked verdict; a miss races once and banks it.
Where the kernels come from: the DAG FFT compiler takes a DFT as an expression DAG and emits straight-line, register-allocated C per instruction set.
The contracts in full: include/vfft.h (support matrix and
buffer signatures) and docs/design/design_contracts.md.