
# 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.
63 lines
1.8 KiB
Rust
63 lines
1.8 KiB
Rust
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());
|
|
});
|
|
}
|