Repository navigation
Releases: go-fft/fft
Release list
v0.28.2
CI only, no library change: the qemu jobs (loong64, ppc64le, riscv64, s390x) run on ubuntu-latest again. They install qemu-user, which works on Ubuntu 26.04 (qemu-user-static is a virtual package there), so the ubuntu-24.04 pin is gone. #87
v0.28.1
Documentation only (#82): the README documents Options.FMA (v0.28.0) — what it changes, when to use it, where it is a no-op, and its measured per-CPU gains and costs. No code change from v0.28.0.
v0.28.0 — opt-in FMA mode
New: an opt-in FMA mode (Options.FMA, with NewPlanWith, NewRealPlanWith, NewPlanNWith, NewRealPlan2With, FFTWith, RFFTWith, FFTNWith). Rounds 41–42.
- Default unchanged: without the option, every transform returns exactly the bits of v0.27.x (checked on Cascade Lake and Zen 3 over 4,200 transforms).
- With FMA, on amd64 CPUs with FMA3, plans use fused multiply-add kernels chosen per pass from a measured table per CPU, so an FMA plan is never slower than the default (worst row 0.990×, within placement noise). Elsewhere the option runs the default kernels.
- Radix 32 with FMA (go-asmgen v0.20.0 builders): on Cascade Lake, complex 1,024 goes from 1.19 to 0.94 × FFTW, RFFT 4,096 from 1.03 to 0.94, complex 256 from 1.05 to 0.96. On Zen 3 radix 32 does not pay; complex 1,024 goes from 1.13 to 1.10 × FFTW.
- Rows within 5% of FFTW (of 24): Zen 3 19 → 20, Cascade Lake 17 → 18.
- Accuracy: relative error against long double on the exact inputs, FMA ÷ default, 0.76–1.08 over 90 transforms. Every FMA kernel is bit-identical to a
math.FMAGo reference. - Every path honours the option: real transforms, Rader/Bluestein, N-D strips (all lengths 2–2000 checked, including 9·p).
- CI: the qemu jobs run on ubuntu-24.04 (
ubuntu-latest26.04 cannot install qemu-user-static).
Details: BENCHMARKS.md, Rounds 41 and 42. #80 (supersedes #77).
v0.27.3
No library change. The SIMD kernel generators moved into go-asmgen (github.com/go-asmgen/asmgen/fft/{amd64,arm64,riscv64,s390x}, v0.17.0): go-fft's generators went from 6,516 lines to 409, and every committed .s regenerates byte-identically (21 files, checked in CI and independently). #78
v0.27.2
Measurements only (no code change): Round 41 — an opt-in FMA mode for the amd64 kernels, measured. As accurate as the default (relative RMS error 0.90–1.04× the default's, ≤ 1.1e-15, against numpy and long-double scipy on the exact input bytes); complex 256 1.07–1.08× faster, RFFT 4096 on Zen 3 1.116 → 1.044 × FFTW, rows within 5% of FFTW Zen 3 18 → 20, Cascade Lake 16 → 18; complex 1024 unchanged; a few rows up to 2.2% slower. The code (branch fma-opt-in-r41, #77) is not merged yet: its FFT kernel generators are first moving into go-asmgen. #76
v0.27.1
Documentation only: performance claims at v0.27.0, recomputed from the raw parity runs (benchmarks/results/current-numbers-v0.27.0/). Within 5% of FFTW or faster: Neoverse-N1 24/24 (all faster), Zen 3 18/24 (17 faster), Cascade Lake 15/24 (14 faster, every 2-D row). README, BENCHMARKS.md and the docs now carry a note on v0.26.3's correctness fix (wrong N-D results on Intel AVX-512 for axes of length 9·p in v0.25.0–v0.26.2). Round 39 disproved "2-D 512² is allocation placement"; the sentence is gone. #75
v0.27.0
Round 39, Cascade Lake (Intel AVX-512): every 2-D parity row now faster than FFTW.
- Wider column strips (cl3StripWidth): an N-D axis spanning ≥ 2^18 elements with lines ≥ 256 apart takes 128 lines (n ≤ 256) or 64: the strip step 1.93–2.36× faster at 512², 1.26× at 1024², up to 2.97× on 3-D axes.
- 2-D rows on the stack-frame kernels on Intel too (cl3FrameRows): 32² 1.29×, 64² 1.14×, 128² 1.06×.
- Round 35's "2-D 512² is allocation placement" did not hold: placement moved it < 10% in one process; the column passes wait on lines the prefetchers do not fetch.
End to end vs v0.26.1 (9 rounds, 4 placements): 2-D 512² 1.219×, 1024² 1.183×, 32² 1.308×, 64² 1.129×; untouched rows 0.99–1.02. FFTW parity: 2-D 64²/128²/256²/512²/1024² 0.937/0.946/0.949/0.883/0.834 (were 1.061/0.981/0.998/1.003/1.025); rows faster than FFTW 10 → 14 of 24. Bit-identical outputs (wide vs narrow strips); keeps v0.26.3's N-D guard. Details: BENCHMARKS.md, Round 39.
v0.26.4
Measurements only (no code change): Round 38 — a radix-32 pass on amd64 was built bit-identical and lost to split radix 8 everywhere it was timed (Zen 3: complex 1024 0.85×, 256 0.81×), so it is not shipped (code on branch perf-r32x-r38). Zen 3's RFFT rows against FFTW after v0.25.0's tail jump moved within the run-to-run spread. #74
v0.26.3 — fixes wrong N-D results on Intel AVX-512
Correctness fix. Upgrade if you run N-D transforms on Intel CPUs with AVX-512.
Affected: v0.25.0, v0.26.0, v0.26.1, v0.26.2, on Intel CPUs with AVX-512 (e.g. Cascade Lake, Ice Lake, Sapphire Rapids) only.
Symptom: FFTN / FFT2 / PlanN (and their inverses) returned wrong values, silently, when an axis other than the last has a length 9·p with p a prime that no Stockham pass handles — 153, 171, 207, 261, 342, … (120 of the lengths up to 2000). 1-D transforms, real transforms, the last axis, and every other CPU (AMD, Intel without AVX-512, arm64, and the other architectures) were correct.
Cause: v0.25.0's radix-9 route made compTakes16(9·p) true while the axis plan of 9·p is Rader or Bluestein; the N-D plan replaced it with a Stockham plan whose passes multiply to 9, not 9·p.
Fix (#73): the strip axis takes the no-radix-16 Stockham plan only when its passes multiply to n, and that plan's constructor now refuses (panics with an internal message) a partial factorization instead of transforming the wrong length. New tests check every strip-axis length 2–2000 and force the radix-9 route on any amd64 CPU, so CI catches this whatever runner it gets.
How it was found: FuzzPublicAPI failed once on a CI runner with AVX-512 (shape [171 22]: FFTN round trip) and passed on rerun on another runner; reproduced deterministically on Cascade Lake.
v0.26.2
Measurements only (no code change): Round 40, Neoverse-N1 parity re-measured at v0.26.1. Faster than FFTW on all 24 rows (unchanged); complex 10007 (Bluestein) 0.72 → 0.689 × FFTW. A/B v0.25.0 vs v0.26.1 (one external harness, 4 heap placements, 9 rotated rounds): CMulTo costs nothing on arm64 — complex 10007 0.980× the time, every round below 1. #70