Last active
May 17, 2026 10:11
-
-
Save Nekrolm/3c56ad837224a8ca9dc91f82b84a8f83 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use bumpalo::Bump; | |
| use criterion::{criterion_group, criterion_main, Criterion}; | |
| use std::hint::black_box; | |
| const N: usize = 10000; | |
| const NUM_IMPLS: usize = 5; | |
| pub trait Handler { | |
| fn handle(&mut self) -> u64; | |
| } | |
| macro_rules! define_impl { | |
| ($name:ident, $idx:expr) => { | |
| pub struct $name { | |
| state: u64, | |
| } | |
| impl $name { | |
| fn new(seed: u64) -> Self { | |
| Self { state: seed } | |
| } | |
| } | |
| impl Handler for $name { | |
| fn handle(&mut self) -> u64 { | |
| let mut x = self.state; | |
| x = x.wrapping_add($idx as u64); | |
| x = x.wrapping_mul(1664525u64.wrapping_add($idx as u64 * 37)); | |
| x ^= x.rotate_left((($idx * 7) % 63) as u32); | |
| self.state = x.wrapping_add(0x9e37_79b9_7f4a_7c15u64.wrapping_mul($idx as u64)); | |
| self.state | |
| } | |
| } | |
| }; | |
| } | |
| define_impl!(Impl1, 1); | |
| define_impl!(Impl2, 2); | |
| define_impl!(Impl3, 3); | |
| define_impl!(Impl4, 4); | |
| define_impl!(Impl5, 5); | |
| // define_impl!(Impl6, 6); | |
| // define_impl!(Impl7, 7); | |
| // define_impl!(Impl8, 8); | |
| // define_impl!(Impl9, 9); | |
| // define_impl!(Impl10, 10); | |
| // define_impl!(Impl11, 11); | |
| // define_impl!(Impl12, 12); | |
| // define_impl!(Impl13, 13); | |
| // define_impl!(Impl14, 14); | |
| // define_impl!(Impl15, 15); | |
| // define_impl!(Impl16, 16); | |
| // define_impl!(Impl17, 17); | |
| // define_impl!(Impl18, 18); | |
| // define_impl!(Impl19, 19); | |
| // define_impl!(Impl20, 20); | |
| pub enum HandleEnum<'a> { | |
| I1(&'a mut Impl1), | |
| I2(&'a mut Impl2), | |
| I3(&'a mut Impl3), | |
| I4(&'a mut Impl4), | |
| I5(&'a mut Impl5), | |
| // I6(&'a mut Impl6), | |
| // I7(&'a mut Impl7), | |
| // I8(&'a mut Impl8), | |
| // I9(&'a mut Impl9), | |
| // I10(&'a mut Impl10), | |
| // I11(&'a mut Impl11), | |
| // I12(&'a mut Impl12), | |
| // I13(&'a mut Impl13), | |
| // I14(&'a mut Impl14), | |
| // I15(&'a mut Impl15), | |
| // I16(&'a mut Impl16), | |
| // I17(&'a mut Impl17), | |
| // I18(&'a mut Impl18), | |
| // I19(&'a mut Impl19), | |
| // I20(&'a mut Impl20), | |
| } | |
| impl<'a> HandleEnum<'a> { | |
| pub fn call(&mut self) -> u64 { | |
| match self { | |
| HandleEnum::I1(v) => v.handle(), | |
| HandleEnum::I2(v) => v.handle(), | |
| HandleEnum::I3(v) => v.handle(), | |
| HandleEnum::I4(v) => v.handle(), | |
| HandleEnum::I5(v) => v.handle(), | |
| // HandleEnum::I6(v) => v.handle(), | |
| // HandleEnum::I7(v) => v.handle(), | |
| // HandleEnum::I8(v) => v.handle(), | |
| // HandleEnum::I9(v) => v.handle(), | |
| // HandleEnum::I10(v) => v.handle(), | |
| // HandleEnum::I11(v) => v.handle(), | |
| // HandleEnum::I12(v) => v.handle(), | |
| // HandleEnum::I13(v) => v.handle(), | |
| // HandleEnum::I14(v) => v.handle(), | |
| // HandleEnum::I15(v) => v.handle(), | |
| // HandleEnum::I16(v) => v.handle(), | |
| // HandleEnum::I17(v) => v.handle(), | |
| // HandleEnum::I18(v) => v.handle(), | |
| // HandleEnum::I19(v) => v.handle(), | |
| // HandleEnum::I20(v) => v.handle(), | |
| } | |
| } | |
| } | |
| fn lcg_next(seed: &mut u64) { | |
| *seed = seed.wrapping_mul(6364136223846793005u64).wrapping_add(1); | |
| } | |
| fn make_enum_vec<'a>(bump: &'a Bump) -> Vec<HandleEnum<'a>> { | |
| let mut v = Vec::with_capacity(N); | |
| let mut seed: u64 = 0x1234_5678_9ABC_DEF0u64; | |
| for i in 0..N { | |
| lcg_next(&mut seed); | |
| let choice = ((seed >> 32) as usize) % NUM_IMPLS; | |
| match choice { | |
| 0 => { | |
| let obj = bump.alloc(Impl1::new(seed ^ i as u64)); | |
| v.push(HandleEnum::I1(obj)); | |
| } | |
| 1 => { | |
| let obj = bump.alloc(Impl2::new(seed ^ i as u64)); | |
| v.push(HandleEnum::I2(obj)); | |
| } | |
| 2 => { | |
| let obj = bump.alloc(Impl3::new(seed ^ i as u64)); | |
| v.push(HandleEnum::I3(obj)); | |
| } | |
| 3 => { | |
| let obj = bump.alloc(Impl4::new(seed ^ i as u64)); | |
| v.push(HandleEnum::I4(obj)); | |
| } | |
| 4 => { | |
| let obj = bump.alloc(Impl5::new(seed ^ i as u64)); | |
| v.push(HandleEnum::I5(obj)); | |
| } | |
| // 5 => { | |
| // let obj = bump.alloc(Impl6::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I6(obj)); | |
| // } | |
| // 6 => { | |
| // let obj = bump.alloc(Impl7::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I7(obj)); | |
| // } | |
| // 7 => { | |
| // let obj = bump.alloc(Impl8::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I8(obj)); | |
| // } | |
| // 8 => { | |
| // let obj = bump.alloc(Impl9::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I9(obj)); | |
| // } | |
| // 9 => { | |
| // let obj = bump.alloc(Impl10::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I10(obj)); | |
| // } | |
| // 10 => { | |
| // let obj = bump.alloc(Impl11::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I11(obj)); | |
| // } | |
| // 11 => { | |
| // let obj = bump.alloc(Impl12::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I12(obj)); | |
| // } | |
| // 12 => { | |
| // let obj = bump.alloc(Impl13::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I13(obj)); | |
| // } | |
| // 13 => { | |
| // let obj = bump.alloc(Impl14::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I14(obj)); | |
| // } | |
| // 14 => { | |
| // let obj = bump.alloc(Impl15::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I15(obj)); | |
| // } | |
| // 15 => { | |
| // let obj = bump.alloc(Impl16::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I16(obj)); | |
| // } | |
| // 16 => { | |
| // let obj = bump.alloc(Impl17::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I17(obj)); | |
| // } | |
| // 17 => { | |
| // let obj = bump.alloc(Impl18::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I18(obj)); | |
| // } | |
| // 18 => { | |
| // let obj = bump.alloc(Impl19::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I19(obj)); | |
| // } | |
| // 19 => { | |
| // let obj = bump.alloc(Impl20::new(seed ^ i as u64)); | |
| // v.push(HandleEnum::I20(obj)); | |
| // } | |
| _ => unreachable!(), | |
| } | |
| } | |
| v | |
| } | |
| fn make_dyn_vec<'a>(bump: &'a Bump) -> Vec<&'a mut dyn Handler> { | |
| let mut v: Vec<&'a mut dyn Handler> = Vec::with_capacity(N); | |
| let mut seed: u64 = 0x1234_5678_9ABC_DEF0u64; | |
| for i in 0..N { | |
| lcg_next(&mut seed); | |
| let choice = ((seed >> 32) as usize) % NUM_IMPLS; | |
| match choice { | |
| 0 => { | |
| let obj = bump.alloc(Impl1::new(seed ^ i as u64)); | |
| v.push(obj as &mut dyn Handler); | |
| } | |
| 1 => { | |
| let obj = bump.alloc(Impl2::new(seed ^ i as u64)); | |
| v.push(obj as &mut dyn Handler); | |
| } | |
| 2 => { | |
| let obj = bump.alloc(Impl3::new(seed ^ i as u64)); | |
| v.push(obj as &mut dyn Handler); | |
| } | |
| 3 => { | |
| let obj = bump.alloc(Impl4::new(seed ^ i as u64)); | |
| v.push(obj as &mut dyn Handler); | |
| } | |
| 4 => { | |
| let obj = bump.alloc(Impl5::new(seed ^ i as u64)); | |
| v.push(obj as &mut dyn Handler); | |
| } | |
| // 5 => { | |
| // let obj = bump.alloc(Impl6::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 6 => { | |
| // let obj = bump.alloc(Impl7::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 7 => { | |
| // let obj = bump.alloc(Impl8::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 8 => { | |
| // let obj = bump.alloc(Impl9::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 9 => { | |
| // let obj = bump.alloc(Impl10::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 10 => { | |
| // let obj = bump.alloc(Impl11::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 11 => { | |
| // let obj = bump.alloc(Impl12::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 12 => { | |
| // let obj = bump.alloc(Impl13::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 13 => { | |
| // let obj = bump.alloc(Impl14::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 14 => { | |
| // let obj = bump.alloc(Impl15::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 15 => { | |
| // let obj = bump.alloc(Impl16::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 16 => { | |
| // let obj = bump.alloc(Impl17::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 17 => { | |
| // let obj = bump.alloc(Impl18::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 18 => { | |
| // let obj = bump.alloc(Impl19::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| // 19 => { | |
| // let obj = bump.alloc(Impl20::new(seed ^ i as u64)); | |
| // v.push(obj as &mut dyn Handler); | |
| // } | |
| _ => unreachable!(), | |
| } | |
| } | |
| v | |
| } | |
| fn bench_enum(c: &mut Criterion) { | |
| let mut group = c.benchmark_group("dispatch_enum"); | |
| group.sample_size(200); | |
| let bump = Bump::new(); | |
| let mut items = make_enum_vec(&bump); | |
| group.bench_function("enum_dispatch", |b| { | |
| b.iter(|| { | |
| let mut sum: u64 = 0; | |
| for it in items.iter_mut() { | |
| sum = sum.wrapping_add(it.call()); | |
| } | |
| black_box(sum); | |
| }) | |
| }); | |
| group.finish(); | |
| } | |
| fn bench_dyn(c: &mut Criterion) { | |
| let mut group = c.benchmark_group("dispatch_dyn"); | |
| group.sample_size(200); | |
| let bump = Bump::new(); | |
| let mut items = make_dyn_vec(&bump); | |
| group.bench_function("dyn_dispatch", |b| { | |
| b.iter(|| { | |
| let mut sum: u64 = 0; | |
| for it in items.iter_mut() { | |
| sum = sum.wrapping_add(it.handle()); | |
| } | |
| black_box(sum); | |
| }) | |
| }); | |
| group.finish(); | |
| } | |
| criterion_group!(benches, bench_dyn, bench_enum); | |
| criterion_main!(benches); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment