bevy/benches/benches/bevy_reflect/function.rs
poopy 15f00278e7
Rename ArgList::push methods to with and add new push methods which take &mut self (#16567)
# Objective

The `ArgList::push` family of methods consume `self` and return a new
`ArgList` which means they can't be used with `&mut ArgList` references.

```rust
fn foo(args: &mut ArgList) {
    args.push_owned(47_i32); // doesn't work :(
}
```

It's typical for `push` methods on other existing types to take `&mut
self`.

## Solution

Renamed the existing push methods to `with_arg`, `with_ref` etc and
added new `push` methods which take `&mut self`.

## Migration Guide

Uses of the `ArgList::push` methods should be replaced with the `with`
counterpart.

<details>

| old | new |
| --- | --- |
| push_arg | with_arg |
| push_ref | with_ref |
| push_mut | with_mut |
| push_owned | with_owned | 
| push_boxed | with_boxed |

</details>
2025-01-28 05:06:50 +00:00

403 lines
16 KiB
Rust

use core::hint::black_box;
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(bench!("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());
})
.bench_function("closure_mut", |b| {
let mut capture = 25;
let closure = |a: i32| capture += a;
b.iter(|| closure.get_function_info());
});
}
fn into(c: &mut Criterion) {
c.benchmark_group(bench!("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_function());
})
.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(bench!("call"))
.bench_function("trait_object", |b| {
b.iter_batched(
|| Box::new(add) as Box<dyn Fn(i32, i32) -> i32>,
|func| func(black_box(75), black_box(25)),
BatchSize::SmallInput,
);
})
.bench_function("function", |b| {
let add = add.into_function();
b.iter_batched(
|| ArgList::new().with_owned(75_i32).with_owned(25_i32),
|args| add.call(args),
BatchSize::SmallInput,
);
})
.bench_function("closure", |b| {
let capture = 25;
let add = (|a: i32| a + capture).into_function();
b.iter_batched(
|| ArgList::new().with_owned(75_i32),
|args| add.call(args),
BatchSize::SmallInput,
);
})
.bench_function("closure_mut", |b| {
let mut capture = 25;
let mut add = (|a: i32| capture += a).into_function_mut();
b.iter_batched(
|| ArgList::new().with_owned(75_i32),
|args| add.call(args),
BatchSize::SmallInput,
);
});
}
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
}
fn complex<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(
_: T0,
_: T1,
_: T2,
_: T3,
_: T4,
_: T5,
_: T6,
_: T7,
_: T8,
_: T9,
) {
}
fn with_overload(c: &mut Criterion) {
c.benchmark_group(bench!("with_overload"))
.bench_function(BenchmarkId::new("simple_overload", 1), |b| {
b.iter_batched(
|| simple::<i8>.into_function(),
|func| func.with_overload(simple::<i16>),
BatchSize::SmallInput,
);
})
.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| {
func.with_overload(complex::<i16, i32, i64, i128, u8, u16, u32, u64, u128, i8>)
},
BatchSize::SmallInput,
);
})
.bench_function(BenchmarkId::new("simple_overload", 3), |b| {
b.iter_batched(
|| simple::<i8>.into_function(),
|func| {
func.with_overload(simple::<i16>)
.with_overload(simple::<i32>)
.with_overload(simple::<i64>)
},
BatchSize::SmallInput,
);
})
.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| {
func.with_overload(complex::<i16, i32, i64, i128, u8, u16, u32, u64, u128, i8>)
.with_overload(complex::<i32, i64, i128, u8, u16, u32, u64, u128, i8, i16>)
.with_overload(complex::<i64, i128, u8, u16, u32, u64, u128, i8, i16, i32>)
},
BatchSize::SmallInput,
);
})
.bench_function(BenchmarkId::new("simple_overload", 10), |b| {
b.iter_batched(
|| simple::<i8>.into_function(),
|func| {
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(BenchmarkId::new("complex_overload", 10), |b| {
b.iter_batched(
|| complex::<i8, i16, i32, i64, i128, u8, u16, u32, u64, u128>.into_function(),
|func| {
func.with_overload(complex::<i16, i32, i64, i128, u8, u16, u32, u64, u128, i8>)
.with_overload(complex::<i32, i64, i128, u8, u16, u32, u64, u128, i8, i16>)
.with_overload(complex::<i64, i128, u8, u16, u32, u64, u128, i8, i16, i32>)
.with_overload(complex::<i128, u8, u16, u32, u64, u128, i8, i16, i32, i64>)
.with_overload(complex::<u8, u16, u32, u64, u128, i8, i16, i32, i64, i128>)
.with_overload(complex::<u16, u32, u64, u128, i8, i16, i32, i64, i128, u8>)
.with_overload(complex::<u32, u64, u128, i8, i16, i32, i64, i128, u8, u16>)
.with_overload(complex::<u64, u128, i8, i16, i32, i64, i128, u8, u16, u32>)
.with_overload(complex::<u128, i8, i16, i32, i64, i128, u8, u16, u32, u64>)
},
BatchSize::SmallInput,
);
})
.bench_function(BenchmarkId::new("nested_simple_overload", 1), |b| {
b.iter_batched(
|| simple::<i8>.into_function(),
|func| func.with_overload(simple::<i16>),
BatchSize::SmallInput,
);
})
.bench_function(BenchmarkId::new("nested_simple_overload", 3), |b| {
b.iter_batched(
|| simple::<i8>.into_function(),
|func| {
func.with_overload(
simple::<i16>.into_function().with_overload(
simple::<i32>.into_function().with_overload(simple::<i64>),
),
)
},
BatchSize::SmallInput,
);
})
.bench_function(BenchmarkId::new("nested_simple_overload", 10), |b| {
b.iter_batched(
|| simple::<i8>.into_function(),
|func| {
func.with_overload(
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(simple::<u128>),
),
),
),
),
),
),
),
)
},
BatchSize::SmallInput,
);
});
}
fn call_overload(c: &mut Criterion) {
c.benchmark_group(bench!("call_overload"))
.bench_function(BenchmarkId::new("simple_overload", 1), |b| {
b.iter_batched(
|| {
(
simple::<i8>.into_function().with_overload(simple::<i16>),
ArgList::new().with_owned(75_i8).with_owned(25_i8),
)
},
|(func, args)| func.call(args),
BatchSize::SmallInput,
);
})
.bench_function(BenchmarkId::new("complex_overload", 1), |b| {
b.iter_batched(
|| {
(
complex::<i8, i16, i32, i64, i128, u8, u16, u32, u64, u128>
.into_function()
.with_overload(
complex::<i16, i32, i64, i128, u8, u16, u32, u64, u128, i8>,
),
ArgList::new()
.with_owned(1_i8)
.with_owned(2_i16)
.with_owned(3_i32)
.with_owned(4_i64)
.with_owned(5_i128)
.with_owned(6_u8)
.with_owned(7_u16)
.with_owned(8_u32)
.with_owned(9_u64)
.with_owned(10_u128),
)
},
|(func, args)| func.call(args),
BatchSize::SmallInput,
);
})
.bench_function(BenchmarkId::new("simple_overload", 3), |b| {
b.iter_batched(
|| {
(
simple::<i8>
.into_function()
.with_overload(simple::<i16>)
.with_overload(simple::<i32>)
.with_overload(simple::<i64>),
ArgList::new().with_owned(75_i32).with_owned(25_i32),
)
},
|(func, args)| func.call(args),
BatchSize::SmallInput,
);
})
.bench_function(BenchmarkId::new("complex_overload", 3), |b| {
b.iter_batched(
|| {
(
complex::<i8, i16, i32, i64, i128, u8, u16, u32, u64, u128>
.into_function()
.with_overload(
complex::<i16, i32, i64, i128, u8, u16, u32, u64, u128, i8>,
)
.with_overload(
complex::<i32, i64, i128, u8, u16, u32, u64, u128, i8, i16>,
)
.with_overload(
complex::<i64, i128, u8, u16, u32, u64, u128, i8, i16, i32>,
),
ArgList::new()
.with_owned(1_i32)
.with_owned(2_i64)
.with_owned(3_i128)
.with_owned(4_u8)
.with_owned(5_u16)
.with_owned(6_u32)
.with_owned(7_u64)
.with_owned(8_u128)
.with_owned(9_i8)
.with_owned(10_i16),
)
},
|(func, args)| func.call(args),
BatchSize::SmallInput,
);
})
.bench_function(BenchmarkId::new("simple_overload", 10), |b| {
b.iter_batched(
|| {
(
simple::<i8>
.into_function()
.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().with_owned(75_u8).with_owned(25_u8),
)
},
|(func, args)| func.call(args),
BatchSize::SmallInput,
);
})
.bench_function(BenchmarkId::new("complex_overload", 10), |b| {
b.iter_batched(
|| {
(
complex::<i8, i16, i32, i64, i128, u8, u16, u32, u64, u128>
.into_function()
.with_overload(
complex::<i16, i32, i64, i128, u8, u16, u32, u64, u128, i8>,
)
.with_overload(
complex::<i32, i64, i128, u8, u16, u32, u64, u128, i8, i16>,
)
.with_overload(
complex::<i64, i128, u8, u16, u32, u64, u128, i8, i16, i32>,
)
.with_overload(
complex::<i128, u8, u16, u32, u64, u128, i8, i16, i32, i64>,
)
.with_overload(
complex::<u8, u16, u32, u64, u128, i8, i16, i32, i64, i128>,
)
.with_overload(
complex::<u16, u32, u64, u128, i8, i16, i32, i64, i128, u8>,
)
.with_overload(
complex::<u32, u64, u128, i8, i16, i32, i64, i128, u8, u16>,
)
.with_overload(
complex::<u64, u128, i8, i16, i32, i64, i128, u8, u16, u32>,
)
.with_overload(
complex::<u128, i8, i16, i32, i64, i128, u8, u16, u32, u64>,
),
ArgList::new()
.with_owned(1_u8)
.with_owned(2_u16)
.with_owned(3_u32)
.with_owned(4_u64)
.with_owned(5_u128)
.with_owned(6_i8)
.with_owned(7_i16)
.with_owned(8_i32)
.with_owned(9_i64)
.with_owned(10_i128),
)
},
|(func, args)| func.call(args),
BatchSize::SmallInput,
);
});
}