/ algorithms / benches / fft / fft.rs
fft.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the deltavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  extern crate criterion;
 17  
 18  use deltavm_algorithms::fft::{DensePolynomial, EvaluationDomain};
 19  use deltavm_curves::bls12_377::Fr as Bls12_377_Fr;
 20  use deltavm_fields::PrimeField;
 21  use deltavm_utilities::TestRng;
 22  
 23  use criterion::{Bencher, BenchmarkId, Criterion, criterion_group, criterion_main};
 24  use std::cmp::min;
 25  
 26  /// Degree bounds to benchmark on
 27  /// e.g. degree bound of 2^{15}, means we do an FFT for a degree (2^{15} - 1)
 28  /// polynomial
 29  const BENCHMARK_MIN_DEGREE: usize = 1 << 15;
 30  const BENCHMARK_MAX_DEGREE: usize = 1 << 22;
 31  const BENCHMARK_LOG_INTERVAL_DEGREE: usize = 1;
 32  
 33  /// Utility function for getting a vector of degrees to benchmark on.
 34  /// Returns vec![2^{min}, 2^{min + interval}, ..., 2^{max}], where:
 35  /// interval = log_interval
 36  /// min      = ceil(log_2(min_degree))
 37  /// max      = ceil(log_2(max_degree))
 38  pub fn size_range(log_interval: usize, min_degree: usize, max_degree: usize) -> Vec<usize> {
 39      let mut to_ret = vec![min_degree.next_power_of_two()];
 40      let interval = 1 << log_interval;
 41  
 42      while *to_ret.last().unwrap() < max_degree {
 43          let next_elem = min(max_degree, interval * to_ret.last().unwrap());
 44          to_ret.push(next_elem);
 45      }
 46  
 47      to_ret
 48  }
 49  
 50  /// Returns vec![2^{min}, 2^{min + interval}, ..., 2^{max}], where:
 51  /// interval = BENCHMARK_LOG_INTERVAL_DEGREE
 52  /// min      = ceil(log_2(BENCHMARK_MIN_DEGREE))
 53  /// max      = ceil(log_2(BENCHMARK_MAX_DEGREE))
 54  fn default_size_range() -> Vec<usize> {
 55      size_range(BENCHMARK_LOG_INTERVAL_DEGREE, BENCHMARK_MIN_DEGREE, BENCHMARK_MAX_DEGREE)
 56  }
 57  
 58  fn setup_bench(c: &mut Criterion, name: &str, bench_fn: fn(&mut Bencher, &usize)) {
 59      let mut group = c.benchmark_group(name);
 60      for degree in default_size_range().iter() {
 61          group.bench_with_input(BenchmarkId::from_parameter(degree), degree, bench_fn);
 62      }
 63      group.finish();
 64  }
 65  
 66  fn create_evaluation_domain<F: PrimeField>(degree: usize) -> (EvaluationDomain<F>, Vec<F>) {
 67      let domain = EvaluationDomain::new(degree).unwrap();
 68      let a = DensePolynomial::<F>::rand(degree - 1, &mut TestRng::default()).coeffs().to_vec();
 69      (domain, a)
 70  }
 71  
 72  fn bench_fft_in_place<F: PrimeField>(b: &mut Bencher, degree: &usize) {
 73      let (domain, mut a) = create_evaluation_domain::<F>(*degree);
 74  
 75      b.iter(|| {
 76          domain.fft_in_place(&mut a);
 77      });
 78  }
 79  
 80  fn bench_ifft_in_place<F: PrimeField>(b: &mut Bencher, degree: &usize) {
 81      let (domain, mut a) = create_evaluation_domain::<F>(*degree);
 82  
 83      b.iter(|| {
 84          domain.ifft_in_place(&mut a);
 85      });
 86  }
 87  
 88  fn bench_coset_fft_in_place<F: PrimeField>(b: &mut Bencher, degree: &usize) {
 89      let (domain, mut a) = create_evaluation_domain::<F>(*degree);
 90  
 91      b.iter(|| {
 92          domain.coset_fft_in_place(&mut a);
 93      });
 94  }
 95  
 96  fn bench_coset_ifft_in_place<F: PrimeField>(b: &mut Bencher, degree: &usize) {
 97      let (domain, mut a) = create_evaluation_domain::<F>(*degree);
 98  
 99      b.iter(|| {
100          domain.coset_ifft_in_place(&mut a);
101      });
102  }
103  
104  fn fft_benches<F: PrimeField>(c: &mut Criterion, name: &str) {
105      let description = format!("{name:?} - subgroup_fft_in_place");
106      setup_bench(c, &description, bench_fft_in_place::<F>);
107      let description = format!("{name:?} - subgroup_ifft_in_place");
108      setup_bench(c, &description, bench_ifft_in_place::<F>);
109      let description = format!("{name:?} - coset_fft_in_place");
110      setup_bench(c, &description, bench_coset_fft_in_place::<F>);
111      let description = format!("{name:?} - coset_ifft_in_place");
112      setup_bench(c, &description, bench_coset_ifft_in_place::<F>);
113  }
114  
115  fn bench_bls12_377(c: &mut Criterion) {
116      fft_benches::<Bls12_377_Fr>(c, "BLS12-377 - radix-2");
117  }
118  
119  criterion_group!(benches, bench_bls12_377);
120  criterion_main!(benches);