_fft256_q15_throughput_bench.nx
buildroot/runtime/_fft256_q15_throughput_bench.nx
about
_fft256_q15_throughput_bench.nx -- 256-point Q15 FFT throughput.
THE primary W1 (automotive sensor / leak detection) workload
baseline per WORKLOAD_TARGETS.md. Acoustic leak detection, brake
pressure analysis, battery thermal classification, motor vibration
FFT-fingerprinting -- every one of these starts with a real-input
FFT in the 256..2048-point range.
Q15 fixed-point (16-bit signed in -1.0..+1.0 range): the industry
default for low-power DSP per ARM CMSIS-DSP, TI C5000, and
every automotive sensor MCU. NishiLang has no native fp, so Q15
is also a natural fit for the substrate.
Algorithm: Cooley-Tukey radix-2 decimation-in-time (DIT). In-place
256-point complex FFT. Twiddle factors generated iteratively at
startup via the angle-addition formula:
cos(t+dt) = cos(t)*cos(dt) - sin(t)*sin(dt)
sin(t+dt) = sin(t)*cos(dt) + cos(t)*sin(dt)
so we hard-code ONE step (cos/sin of 2*pi/256) and grow the table.
Bench: 1000 iterations of 256-point FFT. Reports FFTs/sec +
per-FFT latency in microseconds. Reference targets:
ARM CMSIS-DSP (Cortex-M4 @ 100 MHz, SIMD) ~50K FFTs/sec
FFTW double precision (modern x86_64) ~100K FFTs/sec
Pure-software (this bench) ~1-10K FFTs/sec est
CUDA cuFFT batched ~10M FFTs/sec
Silicon-feedback consumption: rv64im_min_hot_report.nx attribution
over this bench identifies which functions dominate (likely the
butterfly inner loop's multiply + accumulate). PROP_MAC_FUSED
silicon candidate from rv64im_min_hot_report.nx (3000 gates,
2x speedup) is the prime addition target -- THIS bench is the
evidence base for that decision.
Status: SEED. 2026-05-26. Single-stage radix-2; future commits
add split-radix (~40% fewer multiplies) + the SIMD-vector emit
variant when V-ext silicon candidate lands.
dependencies 1 imports · 0 importers
imports: nx_syscalls.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 41 | const NX_FFT_N: i64 = 256 |
| 42 | const NX_FFT_LOG2_N: i64 = 8 |
| 43 | const NX_FFT_Q15_ONE: i64 = 32767 |
| 44 | const NX_FFT_ITERS: i64 = 1000 |
| 47 | const NX_FFT_COS_STEP: i64 = 32757 |
| 48 | const NX_FFT_SIN_STEP: i64 = 804 |
functions
| 56 | func nx_fft_sar15(v: i64) -> i64 |
| 69 | func nx_fft_gen_twiddles(cos_tab: *i64, sin_tab: *i64) -> i64 |
| 89 | func nx_fft_bit_reverse_8(x: i64) -> i64 called by 1: nx_fft_bit_reverse_permute |
| 103 | func nx_fft_bit_reverse_permute(re: *i64, im: *i64) -> i64 |
| 126 | func nx_fft_radix2(re: *i64, im: *i64, cos_tab: *i64, sin_tab: *i64) -> i64 |
| 163 | func main() -> i64 |