yum/gpu_fft

A GPU-friendly FFT

git clone https://git.yummers.dev/yum/gpu_fft

yumNaive DFT now respects workgroup sized144a07

master
7.7 KiB243 linesraw
1use criterion::{BatchSize, Criterion, black_box, criterion_group, criterion_main};
2use gpu_fft::cpu::{
3    fft_v1_hoist, fft_v2_double_buffer, fft_v3_iterative, fft_v4_radix_4, fft_v5_s0_opt,
4    fft_v6_unsafe, fft_v7_radix_8, naive_dft, naive_fft, precompute_twiddles,
5};
6use num::complex::Complex;
7use num::traits::Float;
8
9// Cast one float type to another, truncating if needed.
10fn t0_to_t1<T0: Float, T1: Float>(val: T0) -> T1 {
11    return num::cast(val).unwrap();
12}
13
14// Casts one Complex<T> to another.
15fn complex_to_t<T0: Float, T1: Float>(data: &[Complex<T0>]) -> Vec<Complex<T1>> {
16    data.iter()
17        .map(|c| Complex::new(t0_to_t1(c.re), t0_to_t1(c.im)))
18        .collect()
19}
20
21fn get_data<const N: usize>() -> Vec<Complex<f32>> {
22    let mut data: Vec<Complex<f32>> = Vec::new();
23    data.resize(N, Complex::ZERO);
24    // Randomize data.
25    for i in 0..data.len() {
26        data[i] = Complex::new(rand::random(), rand::random());
27    }
28    data
29}
30
31fn do_dft_benchmark_for_n<const N: usize>(c: &mut Criterion) {
32    let data = get_data::<N>();
33
34    let result_ref: Vec<rustfft::num_complex::Complex<f32>> = complex_to_t(&data);
35
36    c.bench_function(format!("size {}, dft", N).as_str(), |b| {
37        b.iter_batched_ref(
38            || result_ref.clone(),
39            |result_ref| {
40                naive_dft::<f32>(result_ref);
41                black_box(result_ref);
42            },
43            BatchSize::PerIteration,
44        );
45    });
46}
47
48fn do_naive_fft_benchmark_for_n<const N: usize>(c: &mut Criterion) {
49    let data = get_data::<N>();
50
51    let result_ref: Vec<rustfft::num_complex::Complex<f32>> = complex_to_t(&data);
52
53    c.bench_function(format!("size {}, naive fft", N).as_str(), |b| {
54        b.iter_batched_ref(
55            || result_ref.clone(),
56            |result_ref| {
57                naive_fft::<f32>(result_ref);
58                black_box(result_ref);
59            },
60            BatchSize::PerIteration,
61        );
62    });
63}
64
65fn do_fft_v1_benchmark_for_n<const N: usize>(c: &mut Criterion) {
66    let data = get_data::<N>();
67
68    let twiddles = precompute_twiddles(N);
69    let result_ref: Vec<rustfft::num_complex::Complex<f32>> = complex_to_t(&data);
70
71    c.bench_function(format!("size {}, fft v1", N).as_str(), |b| {
72        b.iter_batched_ref(
73            || result_ref.clone(),
74            |result_ref| {
75                fft_v1_hoist::<f32>(result_ref, &twiddles);
76                black_box(result_ref);
77            },
78            BatchSize::PerIteration,
79        );
80    });
81}
82
83fn do_fft_v2_benchmark_for_n<const N: usize>(c: &mut Criterion) {
84    let data = get_data::<N>();
85
86    let twiddles = precompute_twiddles(N);
87    let mut scratch = vec![Complex::new(0.0, 0.0); N];
88    let result_ref: Vec<rustfft::num_complex::Complex<f32>> = complex_to_t(&data);
89
90    c.bench_function(format!("size {}, fft v2", N).as_str(), |b| {
91        b.iter_batched_ref(
92            || result_ref.clone(),
93            |result_ref| {
94                fft_v2_double_buffer::<f32>(result_ref, &mut scratch, &twiddles);
95                black_box(result_ref);
96            },
97            BatchSize::PerIteration,
98        );
99    });
100}
101
102fn do_fft_v3_benchmark_for_n<const N: usize>(c: &mut Criterion) {
103    let data = get_data::<N>();
104
105    let twiddles = precompute_twiddles(N);
106    let mut scratch = vec![Complex::new(0.0, 0.0); N];
107    let result_ref: Vec<rustfft::num_complex::Complex<f32>> = complex_to_t(&data);
108
109    c.bench_function(format!("size {}, fft v3", N).as_str(), |b| {
110        b.iter_batched_ref(
111            || result_ref.clone(),
112            |result_ref| {
113                fft_v3_iterative::<f32>(result_ref, &mut scratch, &twiddles);
114                black_box(result_ref);
115            },
116            BatchSize::PerIteration,
117        );
118    });
119}
120
121fn do_fft_v4_benchmark_for_n<const N: usize>(c: &mut Criterion) {
122    let data = get_data::<N>();
123
124    let twiddles = precompute_twiddles(N);
125    let mut scratch = vec![Complex::new(0.0, 0.0); N];
126    let result_ref: Vec<rustfft::num_complex::Complex<f32>> = complex_to_t(&data);
127
128    c.bench_function(format!("size {}, fft v4", N).as_str(), |b| {
129        b.iter_batched_ref(
130            || result_ref.clone(),
131            |result_ref| {
132                fft_v4_radix_4::<f32>(result_ref, &mut scratch, &twiddles);
133                black_box(result_ref);
134            },
135            BatchSize::PerIteration,
136        );
137    });
138}
139
140fn do_fft_v5_benchmark_for_n<const N: usize>(c: &mut Criterion) {
141    let data = get_data::<N>();
142
143    let twiddles = precompute_twiddles(N);
144    let mut scratch = vec![Complex::new(0.0, 0.0); N];
145    let result_ref: Vec<rustfft::num_complex::Complex<f32>> = complex_to_t(&data);
146
147    c.bench_function(format!("size {}, fft v5", N).as_str(), |b| {
148        b.iter_batched_ref(
149            || result_ref.clone(),
150            |result_ref| {
151                fft_v5_s0_opt::<f32>(result_ref, &mut scratch, &twiddles);
152                black_box(result_ref);
153            },
154            BatchSize::PerIteration,
155        );
156    });
157}
158
159fn do_fft_v6_benchmark_for_n<const N: usize>(c: &mut Criterion) {
160    let data = get_data::<N>();
161
162    let twiddles = precompute_twiddles(N);
163    let mut scratch = vec![Complex::new(0.0, 0.0); N];
164    let result_ref: Vec<rustfft::num_complex::Complex<f32>> = complex_to_t(&data);
165
166    c.bench_function(format!("size {}, fft v6", N).as_str(), |b| {
167        b.iter_batched_ref(
168            || result_ref.clone(),
169            |result_ref| {
170                fft_v6_unsafe::<f32>(result_ref, &mut scratch, &twiddles);
171                black_box(result_ref);
172            },
173            BatchSize::PerIteration,
174        );
175    });
176}
177
178fn do_fft_v7_benchmark_for_n<const N: usize>(c: &mut Criterion) {
179    let data = get_data::<N>();
180
181    let twiddles = precompute_twiddles(N);
182    let mut scratch = vec![Complex::new(0.0, 0.0); N];
183    let result_ref: Vec<rustfft::num_complex::Complex<f32>> = complex_to_t(&data);
184
185    c.bench_function(format!("size {}, fft v7", N).as_str(), |b| {
186        b.iter_batched_ref(
187            || result_ref.clone(),
188            |result_ref| {
189                fft_v7_radix_8::<f32>(result_ref, &mut scratch, &twiddles);
190                black_box(result_ref);
191            },
192            BatchSize::PerIteration,
193        );
194    });
195}
196
197fn do_ref_benchmark_for_n<const N: usize>(c: &mut Criterion) {
198    let data = get_data::<N>();
199
200    let result_ref: Vec<rustfft::num_complex::Complex<f32>> = complex_to_t(&data);
201    let mut ref_planner = rustfft::FftPlanner::<f32>::new();
202    let mut scratch: Vec<rustfft::num_complex::Complex<f32>> =
203        vec![Complex::<f32>::new(0.0, 0.0); N];
204    let ref_fft = ref_planner.plan_fft_forward(result_ref.len());
205
206    c.bench_function(format!("size {}, reference", N).as_str(), |b| {
207        b.iter_batched_ref(
208            || result_ref.clone(),
209            |result_ref| {
210                ref_fft.process_with_scratch(result_ref, &mut scratch);
211                black_box(result_ref);
212            },
213            BatchSize::PerIteration,
214        );
215    });
216}
217
218pub fn criterion_benchmark(c: &mut Criterion) {
219    do_dft_benchmark_for_n::<4096>(c);
220
221    do_fft_v6_benchmark_for_n::<256>(c);
222    do_ref_benchmark_for_n::<256>(c);
223
224    do_fft_v7_benchmark_for_n::<512>(c);
225    do_ref_benchmark_for_n::<512>(c);
226
227    do_fft_v6_benchmark_for_n::<1024>(c);
228    do_ref_benchmark_for_n::<1024>(c);
229
230    do_dft_benchmark_for_n::<4096>(c);
231    do_naive_fft_benchmark_for_n::<4096>(c);
232    do_fft_v1_benchmark_for_n::<4096>(c);
233    do_fft_v2_benchmark_for_n::<4096>(c);
234    do_fft_v3_benchmark_for_n::<4096>(c);
235    do_fft_v4_benchmark_for_n::<4096>(c);
236    do_fft_v5_benchmark_for_n::<4096>(c);
237    do_fft_v6_benchmark_for_n::<4096>(c);
238    do_fft_v7_benchmark_for_n::<4096>(c);
239    do_ref_benchmark_for_n::<4096>(c);
240}
241
242criterion_group!(benches, criterion_benchmark);
243criterion_main!(benches);