bevy/benches/benches/bevy_reflect/function.rs
Gino Valente 91fa4bb649
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.
2024-08-11 03:02:06 +00:00

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());
});
}