mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 21:53:07 +00:00
bevy_reflect: Function reflection benchmarks (#14647)
# Objective It would be good to have benchmarks handy for function reflection as it continues to be worked on. ## Solution Add some basic benchmarks for function reflection. ## Testing To test locally, run the following in the `benches` directory: ``` cargo bench --bench reflect_function ``` ## Results Here are a couple of the results (M1 Max MacBook Pro): <img width="936" alt="Results of benching calling functions vs closures via reflection. Closures average about 40ns, while functions average about 55ns" src="https://github.com/user-attachments/assets/b9a6c585-5fbe-43db-9a7b-f57dbd3815e3"> <img width="936" alt="Results of benching converting functions vs closures into their dynamic representations. Closures average about 34ns, while functions average about 37ns" src="https://github.com/user-attachments/assets/4614560a-7192-4c1e-9ade-7bc5a4ca68e3"> Currently, it seems `DynamicClosure` is just a bit more performant. This is likely due to the fact that `DynamicFunction` stores its function object in an `Arc` instead of a `Box` so that it can be `Send + Sync` (and also `Clone`). We'll likely need to do the same for `DynamicClosure` so I suspect these results to change in the near future.
This commit is contained in:
parent
3e10fd8534
commit
91fa4bb649
2 changed files with 68 additions and 1 deletions
|
@ -15,7 +15,7 @@ bevy_ecs = { path = "../crates/bevy_ecs", features = ["multi_threaded"] }
|
||||||
bevy_hierarchy = { path = "../crates/bevy_hierarchy" }
|
bevy_hierarchy = { path = "../crates/bevy_hierarchy" }
|
||||||
bevy_internal = { path = "../crates/bevy_internal" }
|
bevy_internal = { path = "../crates/bevy_internal" }
|
||||||
bevy_math = { path = "../crates/bevy_math" }
|
bevy_math = { path = "../crates/bevy_math" }
|
||||||
bevy_reflect = { path = "../crates/bevy_reflect" }
|
bevy_reflect = { path = "../crates/bevy_reflect", features = ["functions"] }
|
||||||
bevy_render = { path = "../crates/bevy_render" }
|
bevy_render = { path = "../crates/bevy_render" }
|
||||||
bevy_tasks = { path = "../crates/bevy_tasks" }
|
bevy_tasks = { path = "../crates/bevy_tasks" }
|
||||||
bevy_utils = { path = "../crates/bevy_utils" }
|
bevy_utils = { path = "../crates/bevy_utils" }
|
||||||
|
@ -34,6 +34,11 @@ name = "ecs"
|
||||||
path = "benches/bevy_ecs/benches.rs"
|
path = "benches/bevy_ecs/benches.rs"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "reflect_function"
|
||||||
|
path = "benches/bevy_reflect/function.rs"
|
||||||
|
harness = false
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "reflect_list"
|
name = "reflect_list"
|
||||||
path = "benches/bevy_reflect/list.rs"
|
path = "benches/bevy_reflect/list.rs"
|
||||||
|
|
62
benches/benches/bevy_reflect/function.rs
Normal file
62
benches/benches/bevy_reflect/function.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
use bevy_reflect::func::{ArgList, IntoClosure, TypedFunction};
|
||||||
|
use bevy_reflect::prelude::*;
|
||||||
|
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
|
||||||
|
|
||||||
|
criterion_group!(benches, typed, into, call, clone);
|
||||||
|
criterion_main!(benches);
|
||||||
|
|
||||||
|
fn add(a: i32, b: i32) -> i32 {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
|
||||||
|
fn typed(c: &mut Criterion) {
|
||||||
|
c.benchmark_group("typed")
|
||||||
|
.bench_function("function", |b| {
|
||||||
|
b.iter(|| add.get_function_info());
|
||||||
|
})
|
||||||
|
.bench_function("closure", |b| {
|
||||||
|
let capture = 25;
|
||||||
|
let closure = |a: i32| a + capture;
|
||||||
|
b.iter(|| closure.get_function_info());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into(c: &mut Criterion) {
|
||||||
|
c.benchmark_group("into")
|
||||||
|
.bench_function("function", |b| {
|
||||||
|
b.iter(|| add.into_function());
|
||||||
|
})
|
||||||
|
.bench_function("closure", |b| {
|
||||||
|
let capture = 25;
|
||||||
|
let closure = |a: i32| a + capture;
|
||||||
|
b.iter(|| closure.into_closure());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(c: &mut Criterion) {
|
||||||
|
c.benchmark_group("call")
|
||||||
|
.bench_function("function", |b| {
|
||||||
|
let add = add.into_function();
|
||||||
|
b.iter_batched(
|
||||||
|
|| ArgList::new().push_owned(75_i32).push_owned(25_i32),
|
||||||
|
|args| add.call(args),
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.bench_function("closure", |b| {
|
||||||
|
let capture = 25;
|
||||||
|
let add = (|a: i32| a + capture).into_closure();
|
||||||
|
b.iter_batched(
|
||||||
|
|| ArgList::new().push_owned(75_i32),
|
||||||
|
|args| add.call(args),
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone(c: &mut Criterion) {
|
||||||
|
c.benchmark_group("clone").bench_function("function", |b| {
|
||||||
|
let add = add.into_function();
|
||||||
|
b.iter(|| add.clone());
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in a new issue