KDA Batched 1D Complex FFT
CuTe-DSL forward FFT of each row of a batch of complex fp32 rows, the same
result as torch.fft.fft, for the NVIDIA RTX 5090:
y[b, f] = sum over t of x[b, t] * exp(-2j * pi * f * t / n)
It handles any length: smooth lengths with in-shared-memory and L2-resident multi-pass kernels, primes with Rader's algorithm and everything else with Bluestein's.
1.84x geometric-mean speedup over cuFFT (torch.fft.fft) and 1.60x over
VkFFT across 17 workloads; about 2x on large power-of-two rows, where the
kernel runs at the speed of a device-to-device copy.
Requirements
- NVIDIA GPU with compute capability 12.0; tuned and tested on the RTX 5090 only
- CUDA 13 compatible driver
- PyTorch 2.12.1 with CUDA 13.0 (tested)
nvidia-cutlass-dsl[cu13]==4.6.0(tested)
Usage
import torch
from kernels import get_kernel
fft = get_kernel("humanfia-lab/fft-c2c-1d", version=1, trust_remote_code=True)
x = torch.randn(32, 1 << 22, 2, device="cuda") # [batch, n, (re, im)], fp32
y = fft.run(x) # torch.view_as_real(torch.fft.fft(torch.view_as_complex(x)))
- Any
n >= 1and any batch. The transform is forward and unnormalized. The result is a new[batch, n, 2]fp32 tensor;xis left unchanged. - The first call for a new
(batch, n)compiles its kernels (CuTe DSL JIT); later calls reuse them. Make that first call outside CUDA graph capture; later calls can be captured. - Calls on different CUDA streams may run concurrently.
Accuracy
Everything is computed in fp32: no reduced precision, no tensor cores, no approximate math. Twiddle factors come from tables computed in float64 on the host.
On every workload below, every output element is within 1e-5 of the float64 result, relative to the tensor's RMS or to the element itself. The relative L2 error is 1.1e-7 to 3.4e-7. On the same workloads it is 1.4e-7 to 4.1e-7 for cuFFT, 3.0e-7 to 1.1e-6 for VkFFT and 1.1e-7 to 3.2e-7 for VkFFT with its lookup tables. Repeated calls give bitwise identical results.
Performance
| n | batch | cuFFT (us) | VkFFT (us) | kernel (us) | vs cuFFT | vs VkFFT |
|---|---|---|---|---|---|---|
| 16384 | 8192 | 1411.8 | 2827.2 | 1382.9 | 1.02x | 2.04x |
| 65536 | 2048 | 2872.6 | 2818.7 | 1388.3 | 2.07x | 2.03x |
| 262144 | 512 | 2857.4 | 2821.8 | 1320.2 | 2.16x | 2.14x |
| 2^20 | 128 | 2846.9 | 2835.9 | 1380.0 | 2.06x | 2.06x |
| 2^22 | 32 | 2939.7 | 2870.2 | 1430.2 | 2.06x | 2.01x |
| 2^27 | 1 | 4750.3 | 4527.0 | 2988.9 | 1.59x | 1.51x |
| 400 | 262144 | 1100.2 | 1110.7 | 1106.1 | 0.99x | 1.00x |
| 1000 | 131072 | 1388.3 | 1385.4 | 1381.8 | 1.00x | 1.00x |
| 3072 | 32768 | 1059.7 | 1054.9 | 1058.4 | 1.00x | 1.00x |
| 100000 | 1024 | 3260.6 | 2150.5 | 1078.0 | 3.02x | 1.99x |
| 4093 (prime) | 32768 | 1898.0 | 1662.1 | 1408.4 | 1.35x | 1.18x |
| 10007 (prime) | 8192 | 9691.5 | 4367.6 | 1187.3 | 8.16x | 3.68x |
| 65537 (prime) | 2048 | 21416.1 | 7088.4 | 2418.6 | 8.85x | 2.93x |
| 65536 | 1 | 8.6 | 7.7 | 5.1 | 1.68x | 1.51x |
| 4096 | 64 | 5.4 | 4.4 | 4.3 | 1.26x | 1.04x |
| 1000 | 16 | 2.3 | 2.0 | 1.8 | 1.30x | 1.15x |
| 2^20 | 1 | 21.2 | 19.7 | 16.8 | 1.27x | 1.18x |
| Geomean | vs cuFFT | vs VkFFT | vs the faster of the two |
|---|---|---|---|
| all 17 workloads | 1.84x | 1.60x | 1.54x |
| the 13 large ones | 2.02x | 1.75x | 1.65x |
| the 4 small ones | 1.37x | 1.20x | 1.20x |
On large rows of smooth length the kernel reads and writes every element once: at n = 2^20, batch 128, it moves 1.56 TB/s, as fast as a device-to-device copy of the same tensor. cuFFT and VkFFT pass over DRAM twice there. For n = 16384, 400, 1000 and 3072, cuFFT already passes once, so the kernel only matches it.
Measurements use one RTX 5090 (driver 580.82.07) with CUPTI cold-L2 kernel
time over CUDA graph replay, 3 warmup and 30 measured iterations, median of 3
trials, each trial timing the baseline before and after the kernel. cuFFT is
torch.fft.fft with the cuFFT 12.0 that PyTorch 2.12.1+cu130 ships; the newest
cuFFT, 12.4.0.43, takes the same time to within 0.5%, except for n = 4093,
where it is slower. VkFFT is pyvkfft 2025.1.1 (CUDA backend, out of place),
the faster of its default and lookup-table configurations. Speeds differ by a
few percent between RTX 5090 cards.
Source and licensing
Written by Claude Opus 5.5 in a 12-hour run of KDA (kernel design agents) for
the task fft_c2c_1d, and accepted by the KDA judge. Published from commit
11b486e of humanfia/kda-kernels-internal, directory rtx5090/fft_c2c_1d/,
which also holds its tests. MIT-licensed.
Available functions
run
- Downloads last month
- -
- Kernel Builder
- 375561f


