math/benches/field.rs (219 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
use criterion::{
black_box, criterion_group, criterion_main,
measurement::{Measurement, WallTime},
BatchSize, BenchmarkGroup, BenchmarkId, Criterion,
};
use rand_utils::{rand_array, rand_value, rand_vector};
use std::time::Duration;
use winter_math::{
batch_inversion,
fields::{f128, f62, f64},
fields::{CubeExtension, QuadExtension},
ExtensibleField, FieldElement, StarkField,
};
const SIZES: [usize; 3] = [262_144, 524_288, 1_048_576];
// BATCH INVERSION
// ================================================================================================
pub fn batch_inv(c: &mut Criterion) {
let mut group = c.benchmark_group("batch_inv");
group.sample_size(10);
group.measurement_time(Duration::from_secs(10));
for &size in SIZES.iter() {
let values = rand_vector::<f128::BaseElement>(size);
group.bench_function(BenchmarkId::new("no_coeff", size), |bench| {
bench.iter_with_large_drop(|| batch_inversion(&values));
});
}
group.finish();
}
// SEQUENTIAL OPS
// ================================================================================================
pub fn field_ops<B>(c: &mut Criterion, field_name: &str)
where
B: StarkField + ExtensibleField<2> + ExtensibleField<3>,
{
let mut group = c.benchmark_group(format!("field/{}", field_name));
// --- base field -----------------------------------------------------------------------------
group.bench_function("add", |bench| {
let x = rand_value::<B>();
let y = rand_value::<B>();
bench.iter(|| black_box(x) + black_box(y))
});
group.bench_function("sub", |bench| {
let x = rand_value::<B>();
let y = rand_value::<B>();
bench.iter(|| black_box(x) - black_box(y))
});
group.bench_function("mul", |bench| {
let x = rand_value::<B>();
let y = rand_value::<B>();
bench.iter(|| black_box(x) * black_box(y))
});
group.bench_function("exp", |bench| {
let x = rand_value::<B>();
let y = rand_value::<B>().as_int();
bench.iter(|| x.exp(y))
});
group.bench_function("inv", |bench| {
let x = rand_value::<B>();
bench.iter(|| x.inv())
});
batch_ops::<B, WallTime>(&mut group, "base");
array_ops::<B, WallTime>(&mut group, "base");
// --- quadratic extension --------------------------------------------------------------------
if QuadExtension::<B>::is_supported() {
group.bench_function("quad/add", |bench| {
let x = rand_value::<QuadExtension<B>>();
let y = rand_value::<QuadExtension<B>>();
bench.iter(|| black_box(x) + black_box(y))
});
group.bench_function("quad/sub", |bench| {
let x = rand_value::<QuadExtension<B>>();
let y = rand_value::<QuadExtension<B>>();
bench.iter(|| black_box(x) - black_box(y))
});
group.bench_function("quad/mul", |bench| {
let x = rand_value::<QuadExtension<B>>();
let y = rand_value::<QuadExtension<B>>();
bench.iter(|| black_box(x) * black_box(y))
});
batch_ops::<QuadExtension<B>, WallTime>(&mut group, "quad");
array_ops::<QuadExtension<B>, WallTime>(&mut group, "quad");
}
// --- cubic extension ------------------------------------------------------------------------
if CubeExtension::<B>::is_supported() {
group.bench_function("cube/add", |bench| {
let x = rand_value::<CubeExtension<B>>();
let y = rand_value::<CubeExtension<B>>();
bench.iter(|| black_box(x) + black_box(y))
});
group.bench_function("cube/sub", |bench| {
let x = rand_value::<CubeExtension<B>>();
let y = rand_value::<CubeExtension<B>>();
bench.iter(|| black_box(x) - black_box(y))
});
group.bench_function("cube/mul", |bench| {
let x = rand_value::<CubeExtension<B>>();
let y = rand_value::<CubeExtension<B>>();
bench.iter(|| black_box(x) * black_box(y))
});
}
}
// ARRAY OPS
// ================================================================================================
pub fn array_ops<E: FieldElement, M: Measurement>(group: &mut BenchmarkGroup<M>, extension: &str) {
group.bench_function(format!("{}/array/add", extension), |b| {
b.iter_batched(
|| (rand_array::<E, 100>(), rand_array::<E, 100>()),
|(mut x, y)| {
for (x, y) in x.iter_mut().zip(y) {
*x += y;
}
x
},
BatchSize::SmallInput,
)
});
group.bench_function(format!("{}/array/sub", extension), |b| {
b.iter_batched(
|| (rand_array::<E, 100>(), rand_array::<E, 100>()),
|(mut x, y)| {
for (x, y) in x.iter_mut().zip(y) {
*x -= y;
}
x
},
BatchSize::SmallInput,
)
});
group.bench_function(format!("{}/array/mul", extension), |b| {
b.iter_batched(
|| (rand_array::<E, 100>(), rand_array::<E, 100>()),
|(mut x, y)| {
for (x, y) in x.iter_mut().zip(y) {
*x *= y;
}
x
},
BatchSize::SmallInput,
)
});
}
// BATCH OPS
// ================================================================================================
pub fn batch_ops<E: FieldElement, M: Measurement>(group: &mut BenchmarkGroup<M>, extension: &str) {
group.bench_function(format!("{}/batch/add", extension), |b| {
b.iter_batched(
|| {
(
rand_value::<E>(),
rand_value::<E>(),
rand_value::<E>(),
rand_value::<E>(),
)
},
|(mut a, mut b, mut c, mut d)| {
for _ in 0..25 {
let t0 = a + b;
let t1 = b + c;
let t2 = c + d;
let t3 = d + a;
a = t0;
b = t1;
c = t2;
d = t3;
}
(a, b, c, d)
},
BatchSize::SmallInput,
)
});
group.bench_function(format!("{}/batch/sub", extension), |b| {
b.iter_batched(
|| {
(
rand_value::<E>(),
rand_value::<E>(),
rand_value::<E>(),
rand_value::<E>(),
)
},
|(mut a, mut b, mut c, mut d)| {
for _ in 0..25 {
let t0 = a - b;
let t1 = b - c;
let t2 = c - d;
let t3 = d - a;
a = t0;
b = t1;
c = t2;
d = t3;
}
(a, b, c, d)
},
BatchSize::SmallInput,
)
});
group.bench_function(format!("{}/batch/mul", extension), |b| {
b.iter_batched(
|| {
(
rand_value::<E>(),
rand_value::<E>(),
rand_value::<E>(),
rand_value::<E>(),
)
},
|(mut a, mut b, mut c, mut d)| {
for _ in 0..25 {
let t0 = a * b;
let t1 = b * c;
let t2 = c * d;
let t3 = d * a;
a = t0;
b = t1;
c = t2;
d = t3;
}
(a, b, c, d)
},
BatchSize::SmallInput,
)
});
}
// GENERIC BENCHMARK RUNNER
// ================================================================================================
fn bench_field_ops(c: &mut Criterion) {
field_ops::<f62::BaseElement>(c, "f62");
field_ops::<f64::BaseElement>(c, "f64");
field_ops::<f128::BaseElement>(c, "f128");
}
// CRITERION BOILERPLATE
// ================================================================================================
criterion_group!(field_group, batch_inv, bench_field_ops);
criterion_main!(field_group);