Migrate reflection benchmarks to new naming system (#16986)
# Objective - Please see #16647 for the full reasoning behind this change. ## Solution - Create the `bench!` macro, which generates the name of the benchmark at compile time. Migrating is a single line change, and it will automatically update if you move the benchmark to a different module: ```diff + use benches::bench; fn my_benchmark(c: &mut Criterion) { - c.bench_function("my_benchmark", |b| {}); + c.bench_function(bench!("my_benchmark"), |b| {}); } ``` - Migrate all reflection benchmarks to use `bench!`. - Fix a few places where `black_box()` or Criterion is misused. ## Testing ```sh cd benches # Will take a long time! cargo bench --bench reflect # List out the names of all reflection benchmarks, to ensure I didn't miss anything. cargo bench --bench reflect -- --list # Check for linter warnings. cargo clippy --bench reflect # Run each benchmark once. cargo test --bench reflect ```
This commit is contained in:
parent
3eae8590cc
commit
c03e494a26
@ -7,6 +7,11 @@ license = "MIT OR Apache-2.0"
|
||||
# Do not automatically discover benchmarks, we specify them manually instead.
|
||||
autobenches = false
|
||||
|
||||
[dependencies]
|
||||
# The primary crate that runs and analyzes our benchmarks. This is a regular dependency because the
|
||||
# `bench!` macro refers to it in its documentation.
|
||||
criterion = { version = "0.5.1", features = ["html_reports"] }
|
||||
|
||||
[dev-dependencies]
|
||||
# Bevy crates
|
||||
bevy_app = { path = "../crates/bevy_app" }
|
||||
@ -22,7 +27,6 @@ bevy_tasks = { path = "../crates/bevy_tasks" }
|
||||
bevy_utils = { path = "../crates/bevy_utils" }
|
||||
|
||||
# Other crates
|
||||
criterion = { version = "0.5.1", features = ["html_reports"] }
|
||||
glam = "0.29"
|
||||
rand = "0.8"
|
||||
rand_chacha = "0.3"
|
||||
|
@ -1,14 +1,25 @@
|
||||
use bevy_reflect::func::{ArgList, IntoFunction, IntoFunctionMut, TypedFunction};
|
||||
use criterion::{criterion_group, BatchSize, Criterion};
|
||||
use core::hint::black_box;
|
||||
|
||||
criterion_group!(benches, typed, into, call, overload, clone);
|
||||
use benches::bench;
|
||||
use bevy_reflect::func::{ArgList, IntoFunction, IntoFunctionMut, TypedFunction};
|
||||
use criterion::{criterion_group, BatchSize, BenchmarkId, Criterion};
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
typed,
|
||||
into,
|
||||
call,
|
||||
clone,
|
||||
with_overload,
|
||||
call_overload,
|
||||
);
|
||||
|
||||
fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
|
||||
fn typed(c: &mut Criterion) {
|
||||
c.benchmark_group("typed")
|
||||
c.benchmark_group(bench!("typed"))
|
||||
.bench_function("function", |b| {
|
||||
b.iter(|| add.get_function_info());
|
||||
})
|
||||
@ -25,7 +36,7 @@ fn typed(c: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn into(c: &mut Criterion) {
|
||||
c.benchmark_group("into")
|
||||
c.benchmark_group(bench!("into"))
|
||||
.bench_function("function", |b| {
|
||||
b.iter(|| add.into_function());
|
||||
})
|
||||
@ -36,17 +47,18 @@ fn into(c: &mut Criterion) {
|
||||
})
|
||||
.bench_function("closure_mut", |b| {
|
||||
let mut _capture = 25;
|
||||
// `move` is required here because `into_function_mut()` takes ownership of `self`.
|
||||
let closure = move |a: i32| _capture += a;
|
||||
b.iter(|| closure.into_function_mut());
|
||||
});
|
||||
}
|
||||
|
||||
fn call(c: &mut Criterion) {
|
||||
c.benchmark_group("call")
|
||||
c.benchmark_group(bench!("call"))
|
||||
.bench_function("trait_object", |b| {
|
||||
b.iter_batched(
|
||||
|| Box::new(add) as Box<dyn Fn(i32, i32) -> i32>,
|
||||
|func| func(75, 25),
|
||||
|func| func(black_box(75), black_box(25)),
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
@ -78,8 +90,15 @@ fn call(c: &mut Criterion) {
|
||||
});
|
||||
}
|
||||
|
||||
fn overload(c: &mut Criterion) {
|
||||
fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {
|
||||
fn clone(c: &mut Criterion) {
|
||||
c.benchmark_group(bench!("clone"))
|
||||
.bench_function("function", |b| {
|
||||
let add = add.into_function();
|
||||
b.iter(|| add.clone());
|
||||
});
|
||||
}
|
||||
|
||||
fn simple<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {
|
||||
a + b
|
||||
}
|
||||
|
||||
@ -98,15 +117,16 @@ fn overload(c: &mut Criterion) {
|
||||
) {
|
||||
}
|
||||
|
||||
c.benchmark_group("with_overload")
|
||||
.bench_function("01_simple_overload", |b| {
|
||||
fn with_overload(c: &mut Criterion) {
|
||||
c.benchmark_group(bench!("with_overload"))
|
||||
.bench_function(BenchmarkId::new("simple_overload", 1), |b| {
|
||||
b.iter_batched(
|
||||
|| add::<i8>.into_function(),
|
||||
|func| func.with_overload(add::<i16>),
|
||||
|| simple::<i8>.into_function(),
|
||||
|func| func.with_overload(simple::<i16>),
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("01_complex_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("complex_overload", 1), |b| {
|
||||
b.iter_batched(
|
||||
|| complex::<i8, i16, i32, i64, i128, u8, u16, u32, u64, u128>.into_function(),
|
||||
|func| {
|
||||
@ -115,18 +135,18 @@ fn overload(c: &mut Criterion) {
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("03_simple_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("simple_overload", 3), |b| {
|
||||
b.iter_batched(
|
||||
|| add::<i8>.into_function(),
|
||||
|| simple::<i8>.into_function(),
|
||||
|func| {
|
||||
func.with_overload(add::<i16>)
|
||||
.with_overload(add::<i32>)
|
||||
.with_overload(add::<i64>)
|
||||
func.with_overload(simple::<i16>)
|
||||
.with_overload(simple::<i32>)
|
||||
.with_overload(simple::<i64>)
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("03_complex_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("complex_overload", 3), |b| {
|
||||
b.iter_batched(
|
||||
|| complex::<i8, i16, i32, i64, i128, u8, u16, u32, u64, u128>.into_function(),
|
||||
|func| {
|
||||
@ -137,24 +157,24 @@ fn overload(c: &mut Criterion) {
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("10_simple_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("simple_overload", 10), |b| {
|
||||
b.iter_batched(
|
||||
|| add::<i8>.into_function(),
|
||||
|| simple::<i8>.into_function(),
|
||||
|func| {
|
||||
func.with_overload(add::<i16>)
|
||||
.with_overload(add::<i32>)
|
||||
.with_overload(add::<i64>)
|
||||
.with_overload(add::<i128>)
|
||||
.with_overload(add::<u8>)
|
||||
.with_overload(add::<u16>)
|
||||
.with_overload(add::<u32>)
|
||||
.with_overload(add::<u64>)
|
||||
.with_overload(add::<u128>)
|
||||
func.with_overload(simple::<i16>)
|
||||
.with_overload(simple::<i32>)
|
||||
.with_overload(simple::<i64>)
|
||||
.with_overload(simple::<i128>)
|
||||
.with_overload(simple::<u8>)
|
||||
.with_overload(simple::<u16>)
|
||||
.with_overload(simple::<u32>)
|
||||
.with_overload(simple::<u64>)
|
||||
.with_overload(simple::<u128>)
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("10_complex_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("complex_overload", 10), |b| {
|
||||
b.iter_batched(
|
||||
|| complex::<i8, i16, i32, i64, i128, u8, u16, u32, u64, u128>.into_function(),
|
||||
|func| {
|
||||
@ -171,41 +191,41 @@ fn overload(c: &mut Criterion) {
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("01_nested_simple_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("nested_simple_overload", 1), |b| {
|
||||
b.iter_batched(
|
||||
|| add::<i8>.into_function(),
|
||||
|func| func.with_overload(add::<i16>),
|
||||
|| simple::<i8>.into_function(),
|
||||
|func| func.with_overload(simple::<i16>),
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("03_nested_simple_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("nested_simple_overload", 3), |b| {
|
||||
b.iter_batched(
|
||||
|| add::<i8>.into_function(),
|
||||
|| simple::<i8>.into_function(),
|
||||
|func| {
|
||||
func.with_overload(
|
||||
add::<i16>
|
||||
.into_function()
|
||||
.with_overload(add::<i32>.into_function().with_overload(add::<i64>)),
|
||||
simple::<i16>.into_function().with_overload(
|
||||
simple::<i32>.into_function().with_overload(simple::<i64>),
|
||||
),
|
||||
)
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("10_nested_simple_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("nested_simple_overload", 10), |b| {
|
||||
b.iter_batched(
|
||||
|| add::<i8>.into_function(),
|
||||
|| simple::<i8>.into_function(),
|
||||
|func| {
|
||||
func.with_overload(
|
||||
add::<i16>.into_function().with_overload(
|
||||
add::<i32>.into_function().with_overload(
|
||||
add::<i64>.into_function().with_overload(
|
||||
add::<i128>.into_function().with_overload(
|
||||
add::<u8>.into_function().with_overload(
|
||||
add::<u16>.into_function().with_overload(
|
||||
add::<u32>.into_function().with_overload(
|
||||
add::<u64>
|
||||
simple::<i16>.into_function().with_overload(
|
||||
simple::<i32>.into_function().with_overload(
|
||||
simple::<i64>.into_function().with_overload(
|
||||
simple::<i128>.into_function().with_overload(
|
||||
simple::<u8>.into_function().with_overload(
|
||||
simple::<u16>.into_function().with_overload(
|
||||
simple::<u32>.into_function().with_overload(
|
||||
simple::<u64>
|
||||
.into_function()
|
||||
.with_overload(add::<u128>),
|
||||
.with_overload(simple::<u128>),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -218,13 +238,15 @@ fn overload(c: &mut Criterion) {
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
c.benchmark_group("call_overload")
|
||||
.bench_function("01_simple_overload", |b| {
|
||||
fn call_overload(c: &mut Criterion) {
|
||||
c.benchmark_group(bench!("call_overload"))
|
||||
.bench_function(BenchmarkId::new("simple_overload", 1), |b| {
|
||||
b.iter_batched(
|
||||
|| {
|
||||
(
|
||||
add::<i8>.into_function().with_overload(add::<i16>),
|
||||
simple::<i8>.into_function().with_overload(simple::<i16>),
|
||||
ArgList::new().push_owned(75_i8).push_owned(25_i8),
|
||||
)
|
||||
},
|
||||
@ -232,7 +254,7 @@ fn overload(c: &mut Criterion) {
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("01_complex_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("complex_overload", 1), |b| {
|
||||
b.iter_batched(
|
||||
|| {
|
||||
(
|
||||
@ -258,15 +280,15 @@ fn overload(c: &mut Criterion) {
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("03_simple_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("simple_overload", 3), |b| {
|
||||
b.iter_batched(
|
||||
|| {
|
||||
(
|
||||
add::<i8>
|
||||
simple::<i8>
|
||||
.into_function()
|
||||
.with_overload(add::<i16>)
|
||||
.with_overload(add::<i32>)
|
||||
.with_overload(add::<i64>),
|
||||
.with_overload(simple::<i16>)
|
||||
.with_overload(simple::<i32>)
|
||||
.with_overload(simple::<i64>),
|
||||
ArgList::new().push_owned(75_i32).push_owned(25_i32),
|
||||
)
|
||||
},
|
||||
@ -274,7 +296,7 @@ fn overload(c: &mut Criterion) {
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("03_complex_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("complex_overload", 3), |b| {
|
||||
b.iter_batched(
|
||||
|| {
|
||||
(
|
||||
@ -306,21 +328,21 @@ fn overload(c: &mut Criterion) {
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("10_simple_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("simple_overload", 10), |b| {
|
||||
b.iter_batched(
|
||||
|| {
|
||||
(
|
||||
add::<i8>
|
||||
simple::<i8>
|
||||
.into_function()
|
||||
.with_overload(add::<i16>)
|
||||
.with_overload(add::<i32>)
|
||||
.with_overload(add::<i64>)
|
||||
.with_overload(add::<i128>)
|
||||
.with_overload(add::<u8>)
|
||||
.with_overload(add::<u16>)
|
||||
.with_overload(add::<u32>)
|
||||
.with_overload(add::<u64>)
|
||||
.with_overload(add::<u128>),
|
||||
.with_overload(simple::<i16>)
|
||||
.with_overload(simple::<i32>)
|
||||
.with_overload(simple::<i64>)
|
||||
.with_overload(simple::<i128>)
|
||||
.with_overload(simple::<u8>)
|
||||
.with_overload(simple::<u16>)
|
||||
.with_overload(simple::<u32>)
|
||||
.with_overload(simple::<u64>)
|
||||
.with_overload(simple::<u128>),
|
||||
ArgList::new().push_owned(75_u8).push_owned(25_u8),
|
||||
)
|
||||
},
|
||||
@ -328,7 +350,7 @@ fn overload(c: &mut Criterion) {
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
})
|
||||
.bench_function("10_complex_overload", |b| {
|
||||
.bench_function(BenchmarkId::new("complex_overload", 10), |b| {
|
||||
b.iter_batched(
|
||||
|| {
|
||||
(
|
||||
@ -379,10 +401,3 @@ fn overload(c: &mut Criterion) {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
fn clone(c: &mut Criterion) {
|
||||
c.benchmark_group("clone").bench_function("function", |b| {
|
||||
let add = add.into_function();
|
||||
b.iter(|| add.clone());
|
||||
});
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
use core::{iter, time::Duration};
|
||||
|
||||
use benches::bench;
|
||||
use bevy_reflect::{DynamicList, List};
|
||||
use criterion::{
|
||||
black_box, criterion_group, measurement::Measurement, BatchSize, BenchmarkGroup, BenchmarkId,
|
||||
Criterion, Throughput,
|
||||
black_box, criterion_group, measurement::Measurement, AxisScale, BatchSize, BenchmarkGroup,
|
||||
BenchmarkId, Criterion, PlotConfiguration, Throughput,
|
||||
};
|
||||
|
||||
criterion_group!(
|
||||
@ -14,11 +15,29 @@ criterion_group!(
|
||||
dynamic_list_push
|
||||
);
|
||||
|
||||
// Use a shorter warm-up time (from 3 to 0.5 seconds) and measurement time (from 5 to 4) because we
|
||||
// have so many combinations (>50) to benchmark.
|
||||
const WARM_UP_TIME: Duration = Duration::from_millis(500);
|
||||
const MEASUREMENT_TIME: Duration = Duration::from_secs(4);
|
||||
|
||||
// log10 scaling
|
||||
const SIZES: [usize; 5] = [100_usize, 316, 1000, 3162, 10000];
|
||||
/// An array of list sizes used in benchmarks.
|
||||
///
|
||||
/// This scales logarithmically.
|
||||
const SIZES: [usize; 5] = [100, 316, 1000, 3162, 10000];
|
||||
|
||||
/// Creates a [`BenchmarkGroup`] with common configuration shared by all benchmarks within this
|
||||
/// module.
|
||||
fn create_group<'a, M: Measurement>(c: &'a mut Criterion<M>, name: &str) -> BenchmarkGroup<'a, M> {
|
||||
let mut group = c.benchmark_group(name);
|
||||
|
||||
group
|
||||
.warm_up_time(WARM_UP_TIME)
|
||||
.measurement_time(MEASUREMENT_TIME)
|
||||
// Make the plots logarithmic, matching `SIZES`' scale.
|
||||
.plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic));
|
||||
|
||||
group
|
||||
}
|
||||
|
||||
fn list_apply<M, LBase, LPatch, F1, F2, F3>(
|
||||
group: &mut BenchmarkGroup<M>,
|
||||
@ -53,9 +72,7 @@ fn list_apply<M, LBase, LPatch, F1, F2, F3>(
|
||||
}
|
||||
|
||||
fn concrete_list_apply(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("concrete_list_apply");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("concrete_list_apply"));
|
||||
|
||||
let empty_base = |_: usize| Vec::<u64>::new;
|
||||
let full_base = |size: usize| move || iter::repeat(0).take(size).collect::<Vec<u64>>();
|
||||
@ -77,9 +94,7 @@ fn concrete_list_apply(criterion: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn concrete_list_clone_dynamic(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("concrete_list_clone_dynamic");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("concrete_list_clone_dynamic"));
|
||||
|
||||
for size in SIZES {
|
||||
group.throughput(Throughput::Elements(size as u64));
|
||||
@ -99,9 +114,7 @@ fn concrete_list_clone_dynamic(criterion: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn dynamic_list_push(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("dynamic_list_push");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("dynamic_list_push"));
|
||||
|
||||
for size in SIZES {
|
||||
group.throughput(Throughput::Elements(size as u64));
|
||||
@ -130,9 +143,7 @@ fn dynamic_list_push(criterion: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn dynamic_list_apply(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("dynamic_list_apply");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("dynamic_list_apply"));
|
||||
|
||||
let empty_base = |_: usize| || Vec::<u64>::new().clone_dynamic();
|
||||
let full_base = |size: usize| move || iter::repeat(0).take(size).collect::<Vec<u64>>();
|
||||
|
@ -1,10 +1,11 @@
|
||||
use core::{fmt::Write, iter, time::Duration};
|
||||
|
||||
use benches::bench;
|
||||
use bevy_reflect::{DynamicMap, Map};
|
||||
use bevy_utils::HashMap;
|
||||
use criterion::{
|
||||
black_box, criterion_group, measurement::Measurement, BatchSize, BenchmarkGroup, BenchmarkId,
|
||||
Criterion, Throughput,
|
||||
black_box, criterion_group, measurement::Measurement, AxisScale, BatchSize, BenchmarkGroup,
|
||||
BenchmarkId, Criterion, PlotConfiguration, Throughput,
|
||||
};
|
||||
|
||||
criterion_group!(
|
||||
@ -15,10 +16,30 @@ criterion_group!(
|
||||
dynamic_map_insert
|
||||
);
|
||||
|
||||
// Use a shorter warm-up time (from 3 to 0.5 seconds) and measurement time (from 5 to 4) because we
|
||||
// have so many combinations (>50) to benchmark.
|
||||
const WARM_UP_TIME: Duration = Duration::from_millis(500);
|
||||
const MEASUREMENT_TIME: Duration = Duration::from_secs(4);
|
||||
|
||||
/// An array of list sizes used in benchmarks.
|
||||
///
|
||||
/// This scales logarithmically.
|
||||
const SIZES: [usize; 5] = [100, 316, 1000, 3162, 10000];
|
||||
|
||||
/// Creates a [`BenchmarkGroup`] with common configuration shared by all benchmarks within this
|
||||
/// module.
|
||||
fn create_group<'a, M: Measurement>(c: &'a mut Criterion<M>, name: &str) -> BenchmarkGroup<'a, M> {
|
||||
let mut group = c.benchmark_group(name);
|
||||
|
||||
group
|
||||
.warm_up_time(WARM_UP_TIME)
|
||||
.measurement_time(MEASUREMENT_TIME)
|
||||
// Make the plots logarithmic, matching `SIZES`' scale.
|
||||
.plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic));
|
||||
|
||||
group
|
||||
}
|
||||
|
||||
/// Generic benchmark for applying one `Map` to another.
|
||||
///
|
||||
/// `f_base` is a function which takes an input size and produces a generator
|
||||
@ -55,9 +76,7 @@ fn map_apply<M, MBase, MPatch, F1, F2, F3>(
|
||||
}
|
||||
|
||||
fn concrete_map_apply(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("concrete_map_apply");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("concrete_map_apply"));
|
||||
|
||||
let empty_base = |_: usize| HashMap::<u64, u64>::default;
|
||||
|
||||
@ -131,9 +150,7 @@ fn u64_to_n_byte_key(k: u64, n: usize) -> String {
|
||||
}
|
||||
|
||||
fn dynamic_map_apply(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("dynamic_map_apply");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("dynamic_map_apply"));
|
||||
|
||||
let empty_base = |_: usize| DynamicMap::default;
|
||||
|
||||
@ -199,9 +216,7 @@ fn dynamic_map_apply(criterion: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn dynamic_map_get(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("dynamic_map_get");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("dynamic_map_get"));
|
||||
|
||||
for size in SIZES {
|
||||
group.throughput(Throughput::Elements(size as u64));
|
||||
@ -250,9 +265,7 @@ fn dynamic_map_get(criterion: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn dynamic_map_insert(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("dynamic_map_insert");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("dynamic_map_insert"));
|
||||
|
||||
for size in SIZES {
|
||||
group.throughput(Throughput::Elements(size as u64));
|
||||
|
@ -1,5 +1,6 @@
|
||||
use core::{fmt::Write, str, time::Duration};
|
||||
|
||||
use benches::bench;
|
||||
use bevy_reflect::ParsedPath;
|
||||
use criterion::{black_box, criterion_group, BatchSize, BenchmarkId, Criterion, Throughput};
|
||||
use rand::{distributions::Uniform, Rng, SeedableRng};
|
||||
@ -11,7 +12,7 @@ const WARM_UP_TIME: Duration = Duration::from_millis(500);
|
||||
const MEASUREMENT_TIME: Duration = Duration::from_secs(2);
|
||||
const SAMPLE_SIZE: usize = 500;
|
||||
const NOISE_THRESHOLD: f64 = 0.03;
|
||||
const SIZES: [usize; 6] = [100, 3160, 1000, 3_162, 10_000, 24_000];
|
||||
const SIZES: [usize; 6] = [100, 316, 1_000, 3_162, 10_000, 24_000];
|
||||
|
||||
fn deterministic_rand() -> ChaCha8Rng {
|
||||
ChaCha8Rng::seed_from_u64(42)
|
||||
@ -66,23 +67,32 @@ fn mk_paths(size: usize) -> impl FnMut() -> String {
|
||||
}
|
||||
|
||||
fn parse_reflect_path(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("parse_reflect_path");
|
||||
let mut group = criterion.benchmark_group(bench!("parse_reflect_path"));
|
||||
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
group.sample_size(SAMPLE_SIZE);
|
||||
group.noise_threshold(NOISE_THRESHOLD);
|
||||
let group = &mut group;
|
||||
|
||||
for size in SIZES {
|
||||
group.throughput(Throughput::Elements(size as u64));
|
||||
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("parse_reflect_path", size),
|
||||
BenchmarkId::from_parameter(size),
|
||||
&size,
|
||||
|bencher, &size| {
|
||||
let mk_paths = mk_paths(size);
|
||||
bencher.iter_batched(
|
||||
mk_paths,
|
||||
|path| assert!(ParsedPath::parse(black_box(&path)).is_ok()),
|
||||
|path| {
|
||||
let parsed_path = black_box(ParsedPath::parse(black_box(&path)));
|
||||
|
||||
// When `cargo test --benches` is run, each benchmark is run once. This
|
||||
// verifies that we are benchmarking a successful parse without it
|
||||
// affecting the recorded time.
|
||||
#[cfg(test)]
|
||||
assert!(parsed_path.is_ok());
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
},
|
||||
|
@ -1,7 +1,11 @@
|
||||
use core::time::Duration;
|
||||
|
||||
use benches::bench;
|
||||
use bevy_reflect::{DynamicStruct, GetField, PartialReflect, Reflect, Struct};
|
||||
use criterion::{black_box, criterion_group, BatchSize, BenchmarkId, Criterion, Throughput};
|
||||
use criterion::{
|
||||
black_box, criterion_group, measurement::Measurement, AxisScale, BatchSize, BenchmarkGroup,
|
||||
BenchmarkId, Criterion, PlotConfiguration, Throughput,
|
||||
};
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
@ -19,10 +23,22 @@ const WARM_UP_TIME: Duration = Duration::from_millis(500);
|
||||
const MEASUREMENT_TIME: Duration = Duration::from_secs(4);
|
||||
const SIZES: [usize; 4] = [16, 32, 64, 128];
|
||||
|
||||
/// Creates a [`BenchmarkGroup`] with common configuration shared by all benchmarks within this
|
||||
/// module.
|
||||
fn create_group<'a, M: Measurement>(c: &'a mut Criterion<M>, name: &str) -> BenchmarkGroup<'a, M> {
|
||||
let mut group = c.benchmark_group(name);
|
||||
|
||||
group
|
||||
.warm_up_time(WARM_UP_TIME)
|
||||
.measurement_time(MEASUREMENT_TIME)
|
||||
// Make the plots logarithmic, matching `SIZES`' scale.
|
||||
.plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic));
|
||||
|
||||
group
|
||||
}
|
||||
|
||||
fn concrete_struct_field(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("concrete_struct_field");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("concrete_struct_field"));
|
||||
|
||||
let structs: [Box<dyn Struct>; 4] = [
|
||||
Box::new(Struct16::default()),
|
||||
@ -44,7 +60,7 @@ fn concrete_struct_field(criterion: &mut Criterion) {
|
||||
|
||||
bencher.iter(|| {
|
||||
for name in &field_names {
|
||||
s.field(black_box(name));
|
||||
black_box(s.field(black_box(name)));
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -53,9 +69,7 @@ fn concrete_struct_field(criterion: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn concrete_struct_apply(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("concrete_struct_apply");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("concrete_struct_apply"));
|
||||
|
||||
// Use functions that produce trait objects of varying concrete types as the
|
||||
// input to the benchmark.
|
||||
@ -111,9 +125,7 @@ fn concrete_struct_apply(criterion: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn concrete_struct_type_info(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("concrete_struct_type_info");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("concrete_struct_type_info"));
|
||||
|
||||
let structs: [(Box<dyn Struct>, Box<dyn Struct>); 5] = [
|
||||
(
|
||||
@ -145,23 +157,21 @@ fn concrete_struct_type_info(criterion: &mut Criterion) {
|
||||
BenchmarkId::new("NonGeneric", field_count),
|
||||
&standard,
|
||||
|bencher, s| {
|
||||
bencher.iter(|| black_box(s.get_represented_type_info()));
|
||||
bencher.iter(|| s.get_represented_type_info());
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("Generic", field_count),
|
||||
&generic,
|
||||
|bencher, s| {
|
||||
bencher.iter(|| black_box(s.get_represented_type_info()));
|
||||
bencher.iter(|| s.get_represented_type_info());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn concrete_struct_clone(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("concrete_struct_clone");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("concrete_struct_clone"));
|
||||
|
||||
let structs: [(Box<dyn Struct>, Box<dyn Struct>); 5] = [
|
||||
(
|
||||
@ -193,23 +203,21 @@ fn concrete_struct_clone(criterion: &mut Criterion) {
|
||||
BenchmarkId::new("NonGeneric", field_count),
|
||||
&standard,
|
||||
|bencher, s| {
|
||||
bencher.iter(|| black_box(s.clone_dynamic()));
|
||||
bencher.iter(|| s.clone_dynamic());
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("Generic", field_count),
|
||||
&generic,
|
||||
|bencher, s| {
|
||||
bencher.iter(|| black_box(s.clone_dynamic()));
|
||||
bencher.iter(|| s.clone_dynamic());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn dynamic_struct_clone(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("dynamic_struct_clone");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("dynamic_struct_clone"));
|
||||
|
||||
let structs: [Box<dyn Struct>; 5] = [
|
||||
Box::new(Struct1::default().clone_dynamic()),
|
||||
@ -226,16 +234,14 @@ fn dynamic_struct_clone(criterion: &mut Criterion) {
|
||||
BenchmarkId::from_parameter(field_count),
|
||||
&s,
|
||||
|bencher, s| {
|
||||
bencher.iter(|| black_box(s.clone_dynamic()));
|
||||
bencher.iter(|| s.clone_dynamic());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn dynamic_struct_apply(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("dynamic_struct_apply");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("dynamic_struct_apply"));
|
||||
|
||||
let patches: &[(fn() -> Box<dyn PartialReflect>, usize)] = &[
|
||||
(|| Box::new(Struct16::default()), 16),
|
||||
@ -293,9 +299,7 @@ fn dynamic_struct_apply(criterion: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn dynamic_struct_insert(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("dynamic_struct_insert");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("dynamic_struct_insert"));
|
||||
|
||||
for field_count in SIZES {
|
||||
group.throughput(Throughput::Elements(field_count as u64));
|
||||
@ -325,9 +329,7 @@ fn dynamic_struct_insert(criterion: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn dynamic_struct_get_field(criterion: &mut Criterion) {
|
||||
let mut group = criterion.benchmark_group("dynamic_struct_get");
|
||||
group.warm_up_time(WARM_UP_TIME);
|
||||
group.measurement_time(MEASUREMENT_TIME);
|
||||
let mut group = create_group(criterion, bench!("dynamic_struct_get_field"));
|
||||
|
||||
for field_count in SIZES {
|
||||
group.throughput(Throughput::Elements(field_count as u64));
|
||||
@ -342,9 +344,7 @@ fn dynamic_struct_get_field(criterion: &mut Criterion) {
|
||||
}
|
||||
|
||||
let field = black_box("field_63");
|
||||
bencher.iter(|| {
|
||||
black_box(s.get_field::<()>(field));
|
||||
});
|
||||
bencher.iter(|| s.get_field::<()>(field));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
44
benches/src/lib.rs
Normal file
44
benches/src/lib.rs
Normal file
@ -0,0 +1,44 @@
|
||||
/// Automatically generates the qualified name of a benchmark given its function name and module
|
||||
/// path.
|
||||
///
|
||||
/// This macro takes a single string literal as input and returns a [`&'static str`](str). Its
|
||||
/// result is determined at compile-time. If you need to create variations of a benchmark name
|
||||
/// based on its input, use this in combination with [`BenchmarkId`](criterion::BenchmarkId).
|
||||
///
|
||||
/// # When to use this
|
||||
///
|
||||
/// Use this macro to name benchmarks that are not within a group and benchmark groups themselves.
|
||||
/// You'll most commonly use this macro with:
|
||||
///
|
||||
/// - [`Criterion::bench_function()`](criterion::Criterion::bench_function)
|
||||
/// - [`Criterion::bench_with_input()`](criterion::Criterion::bench_with_input)
|
||||
/// - [`Criterion::benchmark_group()`](criterion::Criterion::benchmark_group)
|
||||
///
|
||||
/// You do not want to use this macro with
|
||||
/// [`BenchmarkGroup::bench_function()`](criterion::BenchmarkGroup::bench_function) or
|
||||
/// [`BenchmarkGroup::bench_with_input()`](criterion::BenchmarkGroup::bench_with_input), because
|
||||
/// the group they are in already has the qualified path in it.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// mod ecs {
|
||||
/// mod query {
|
||||
/// use criterion::Criterion;
|
||||
/// use benches::bench;
|
||||
///
|
||||
/// fn iter(c: &mut Criterion) {
|
||||
/// // Benchmark name ends in `ecs::query::iter`.
|
||||
/// c.bench_function(bench!("iter"), |b| {
|
||||
/// // ...
|
||||
/// });
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! bench {
|
||||
($name:literal) => {
|
||||
concat!(module_path!(), "::", $name)
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user