#![feature(unboxed_closures)]
#![feature(fn_traits)]
#![feature(test)]
#![allow(non_camel_case_types)]
extern crate test;
use test::Bencher;
use hlist2::*;
macro_rules! function_body {
($t:expr) => {
$t * $t - $t + 1.
};
}
const N_S: usize = 5;
const N_L: usize = 100;
fn function(t: f64) -> f64 {
function_body!(t)
}
struct struct_method;
impl struct_method {
pub fn eval(&self, t: f64) -> f64 {
function_body!(t)
}
}
struct struct_fn_trait;
impl FnOnce<(f64,)> for struct_fn_trait {
type Output = f64;
extern "rust-call" fn call_once(self, arg: (f64,)) -> Self::Output {
function_body!(arg.0)
}
}
impl FnMut<(f64,)> for struct_fn_trait {
#[inline]
extern "rust-call" fn call_mut(&mut self, arg: (f64,)) -> Self::Output {
function_body!(arg.0)
}
}
impl Fn<(f64,)> for struct_fn_trait {
extern "rust-call" fn call(&self, arg: (f64,)) -> Self::Output {
function_body!(arg.0)
}
}
fn closure_1() -> impl Copy + Fn(f64) -> f64 {
|t: f64| function_body!(t)
}
fn closure_2() -> impl Copy + Fn(f64) -> f64 {
|t: f64| function_body!(t)
}
fn closure_3() -> impl Copy + Fn(f64) -> f64 {
|t: f64| function_body!(t)
}
fn closure_4() -> impl Copy + Fn(f64) -> f64 {
|t: f64| function_body!(t)
}
fn closure_5() -> impl Copy + Fn(f64) -> f64 {
|t: f64| function_body!(t)
}
#[bench]
fn bench_none(b: &mut Bencher) {
b.iter(|| {})
}
#[bench]
fn bench_single_expression(b: &mut Bencher) {
b.iter(|| {
let t = test::black_box(0.);
function_body!(t)
})
}
#[bench]
fn bench_single_function(b: &mut Bencher) {
b.iter(|| {
let t = test::black_box(0.);
function(t)
})
}
#[bench]
fn bench_single_closure(b: &mut Bencher) {
let f = closure_1();
b.iter(|| {
let t = test::black_box(0.);
f(t)
})
}
#[bench]
fn bench_single_ref_dyn_closure(b: &mut Bencher) {
let f = closure_1();
let f : &dyn Fn(f64) -> f64 = &f;
b.iter(|| {
let t = test::black_box(0.);
f(t)
})
}
#[bench]
fn bench_single_boxed_closure(b: &mut Bencher) {
let f: Box<dyn Fn(f64) -> f64> = Box::new(closure_1());
b.iter(|| {
let t = test::black_box(0.);
f(t)
})
}
#[bench]
fn bench_single_struct_method(b: &mut Bencher) {
let f = struct_method;
b.iter(|| {
let t = test::black_box(0.);
f.eval(t)
})
}
#[bench]
fn bench_single_struct_fn_trait(b: &mut Bencher) {
let f = struct_fn_trait;
b.iter(|| {
let t = test::black_box(0.);
f(t)
})
}
#[bench]
fn bench_collection_small_array_of_closure1(b: &mut Bencher) {
let a: [_; N_S] = std::array::from_fn(|_| closure_1());
b.iter(|| {
for f in a.iter() {
let t = test::black_box(0.);
f(t);
}
})
}
#[bench]
fn bench_collection_large_array_of_closure1(b: &mut Bencher) {
let a: [_; N_L] = std::array::from_fn(|_| closure_1());
b.iter(|| {
for f in a.iter() {
let t = test::black_box(0.);
f(t);
}
})
}
#[bench]
fn bench_collection_small_array_of_boxed_closures(b: &mut Bencher) {
let a: [Box<dyn Fn(f64) -> f64>; N_S] = std::array::from_fn(|i| {
let b: Box<dyn Fn(f64) -> f64> = match i % 5 {
0 => Box::new(closure_1()),
1 => Box::new(closure_2()),
2 => Box::new(closure_3()),
3 => Box::new(closure_4()),
4 => Box::new(closure_5()),
_ => unreachable!(),
};
b
});
b.iter(|| {
for f in a.iter() {
let t = test::black_box(0.);
f(t);
}
})
}
#[bench]
fn bench_collection_large_array_of_boxed_closures(b: &mut Bencher) {
let a: [Box<dyn Fn(f64) -> f64>; N_L] = std::array::from_fn(|i| {
let b: Box<dyn Fn(f64) -> f64> = match i % 5 {
0 => Box::new(closure_1()),
1 => Box::new(closure_2()),
2 => Box::new(closure_3()),
3 => Box::new(closure_4()),
4 => Box::new(closure_5()),
_ => unreachable!(),
};
b
});
b.iter(|| {
for f in a.iter() {
let t = test::black_box(0.);
f(t);
}
})
}
#[bench]
fn bench_collection_small_vec_of_closure1(b: &mut Bencher) {
let a: Vec<_> = (0..N_S).map(|_| closure_1()).collect();
b.iter(|| {
for f in a.iter() {
let t = test::black_box(0.);
f(t);
}
})
}
#[bench]
fn bench_collection_large_vec_of_closure1(b: &mut Bencher) {
let a: Vec<_> = (0..N_L).map(|_| closure_1()).collect();
b.iter(|| {
for f in a.iter() {
let t = test::black_box(0.);
f(t);
}
})
}
#[bench]
fn bench_collection_small_vec_of_boxed_closures(b: &mut Bencher) {
let a: Vec<Box<dyn Fn(f64) -> f64>> = (0..N_S)
.map(|i| {
let b: Box<dyn Fn(f64) -> f64> = match i % 5 {
0 => Box::new(closure_1()),
1 => Box::new(closure_2()),
2 => Box::new(closure_3()),
3 => Box::new(closure_4()),
4 => Box::new(closure_5()),
_ => unreachable!(),
};
b
})
.collect();
b.iter(|| {
for f in a.iter() {
let t = test::black_box(0.);
f(t);
}
})
}
#[bench]
fn bench_collection_large_vec_of_boxed_closures(b: &mut Bencher) {
let a: Vec<Box<dyn Fn(f64) -> f64>> = (0..N_L)
.map(|i| {
let b: Box<dyn Fn(f64) -> f64> = match i % 5 {
0 => Box::new(closure_1()),
1 => Box::new(closure_2()),
2 => Box::new(closure_3()),
3 => Box::new(closure_4()),
4 => Box::new(closure_5()),
_ => unreachable!(),
};
b
})
.collect();
b.iter(|| {
for f in a.iter() {
let t = test::black_box(0.);
f(t);
}
})
}
#[bench]
fn bench_collection_small_hlist_of_closure1_for_loop(b: &mut Bencher) {
let hl = hlist2::hlist![
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
];
assert_eq!(N_S, hl.len());
b.iter(|| {
for f in &hl {
let t = test::black_box(0.);
f(t);
}
})
}
#[bench]
fn bench_collection_small_hlist_of_closures_map(b: &mut Bencher) {
let hl = hlist2::hlist![
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
];
assert_eq!(N_S, hl.len());
use hlist2::ops::*;
struct MyMapFn(f64);
impl<T> MapFn<T> for MyMapFn
where
T: Fn(f64) -> f64,
{
type Output = f64;
fn map(&mut self, f: T) -> Self::Output {
f(self.0)
}
}
b.iter(|| {
let t = test::black_box(0.);
hl.map(Mapper(MyMapFn(t)))
});
}
#[bench]
fn bench_collection_large_hlist_of_closure1_for_loop(b: &mut Bencher) {
let hl = hlist2::hlist![
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
closure_1(),
];
assert_eq!(N_L, hl.len());
b.iter(|| {
for f in &hl {
let t = test::black_box(0.);
f(t);
}
})
}
#[bench]
fn bench_collection_large_hlist_of_closure1_map(b: &mut Bencher) {
let hl = hlist2::hlist![
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
closure_1(),
closure_2(),
closure_3(),
closure_4(),
closure_5(),
];
assert_eq!(N_L, hl.len());
use hlist2::ops::*;
struct MyMapFn(f64);
impl<T> MapFn<T> for MyMapFn
where
T: Fn(f64) -> f64,
{
type Output = f64;
fn map(&mut self, f: T) -> Self::Output {
f(self.0)
}
}
b.iter(|| {
let t = test::black_box(0.);
hl.map(Mapper(MyMapFn(t)))
})
}