182 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use criterion::*;
 | |
| 
 | |
| use itertools::*;
 | |
| use legion::prelude::*;
 | |
| use rayon::join;
 | |
| 
 | |
| #[derive(Copy, Clone, Debug, PartialEq)]
 | |
| struct A(f32);
 | |
| 
 | |
| #[derive(Copy, Clone, Debug, PartialEq)]
 | |
| struct B(f32);
 | |
| 
 | |
| #[derive(Copy, Clone, Debug, PartialEq)]
 | |
| struct C(f32);
 | |
| 
 | |
| #[derive(Copy, Clone, Debug)]
 | |
| enum Variants {
 | |
|     AB(A, B),
 | |
|     AC(A, C),
 | |
| }
 | |
| 
 | |
| fn index(v: Variants) -> u8 {
 | |
|     match v {
 | |
|         Variants::AB(_, _) => 0,
 | |
|         Variants::AC(_, _) => 1,
 | |
|     }
 | |
| }
 | |
| 
 | |
| fn generate(i: u8) -> Variants {
 | |
|     match i {
 | |
|         0 => Variants::AB(A(0.0), B(0.0)),
 | |
|         _ => Variants::AC(A(0.0), C(0.0)),
 | |
|     }
 | |
| }
 | |
| 
 | |
| fn data(n: usize) -> Vec<Variants> {
 | |
|     let mut v = Vec::<Variants>::new();
 | |
| 
 | |
|     for _ in 0..n {
 | |
|         v.push(generate(0));
 | |
|     }
 | |
| 
 | |
|     for _ in 0..n {
 | |
|         v.push(generate(1));
 | |
|     }
 | |
| 
 | |
|     v
 | |
| }
 | |
| 
 | |
| fn setup(data: &[Variants]) -> World {
 | |
|     let universe = Universe::new();
 | |
|     let mut world = universe.create_world();
 | |
| 
 | |
|     for (i, group) in &data.iter().group_by(|x| index(**x)) {
 | |
|         match i {
 | |
|             0 => world.insert(
 | |
|                 (),
 | |
|                 group
 | |
|                     .map(|x| {
 | |
|                         if let Variants::AB(a, b) = x {
 | |
|                             (*a, *b)
 | |
|                         } else {
 | |
|                             panic!();
 | |
|                         }
 | |
|                     })
 | |
|                     .collect::<Vec<_>>(),
 | |
|             ),
 | |
|             _ => world.insert(
 | |
|                 (),
 | |
|                 group
 | |
|                     .map(|x| {
 | |
|                         if let Variants::AC(a, c) = x {
 | |
|                             (*a, *c)
 | |
|                         } else {
 | |
|                             panic!();
 | |
|                         }
 | |
|                     })
 | |
|                     .collect::<Vec<_>>(),
 | |
|             ),
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     world
 | |
| }
 | |
| 
 | |
| fn setup_ideal(data: &[Variants]) -> (Vec<(A, B)>, Vec<(A, C)>) {
 | |
|     let mut ab = Vec::<(A, B)>::new();
 | |
|     let mut ac = Vec::<(A, C)>::new();
 | |
| 
 | |
|     for v in data {
 | |
|         match v {
 | |
|             Variants::AB(a, b) => ab.push((*a, *b)),
 | |
|             Variants::AC(a, c) => ac.push((*a, *c)),
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     (ab, ac)
 | |
| }
 | |
| 
 | |
| fn ideal(ab: &mut Vec<(A, B)>, ac: &mut Vec<(A, C)>) {
 | |
|     for (a, b) in ab.iter_mut() {
 | |
|         b.0 = a.0;
 | |
|     }
 | |
| 
 | |
|     for (a, c) in ac.iter_mut() {
 | |
|         c.0 = a.0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| fn sequential(world: &mut World) {
 | |
|     for (mut b, a) in <(Write<B>, Read<A>)>::query().iter_mut(world) {
 | |
|         b.0 = a.0;
 | |
|     }
 | |
| 
 | |
|     for (mut c, a) in <(Write<C>, Read<A>)>::query().iter_mut(world) {
 | |
|         c.0 = a.0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| fn parallel(world: &mut World) {
 | |
|     join(
 | |
|         || unsafe {
 | |
|             for (mut b, a) in <(Write<B>, Read<A>)>::query().iter_unchecked(&world) {
 | |
|                 b.0 = a.0;
 | |
|             }
 | |
|         },
 | |
|         || unsafe {
 | |
|             for (mut c, a) in <(Write<C>, Read<A>)>::query().iter_unchecked(&world) {
 | |
|                 c.0 = a.0;
 | |
|             }
 | |
|         },
 | |
|     );
 | |
| }
 | |
| 
 | |
| fn par_for_each_mut(world: &mut World) {
 | |
|     join(
 | |
|         || unsafe {
 | |
|             <(Write<B>, Read<A>)>::query().par_for_each_unchecked(&world, |(mut b, a)| {
 | |
|                 b.0 = a.0;
 | |
|             });
 | |
|         },
 | |
|         || unsafe {
 | |
|             <(Write<C>, Read<A>)>::query().par_for_each_unchecked(&world, |(mut c, a)| {
 | |
|                 c.0 = a.0;
 | |
|             });
 | |
|         },
 | |
|     );
 | |
| }
 | |
| 
 | |
| fn bench_ordered(c: &mut Criterion) {
 | |
|     c.bench(
 | |
|         "concurrent queries",
 | |
|         ParameterizedBenchmark::new(
 | |
|             "sequential ideal",
 | |
|             |b, n| {
 | |
|                 let data = data(*n);
 | |
|                 let (mut ab, mut ac) = setup_ideal(&data);
 | |
|                 b.iter(|| ideal(&mut ab, &mut ac));
 | |
|             },
 | |
|             (1..11).map(|i| i * 1000),
 | |
|         )
 | |
|         .with_function("sequential", |b, n| {
 | |
|             let data = data(*n);
 | |
|             let mut world = setup(&data);
 | |
|             b.iter(|| sequential(&mut world));
 | |
|         })
 | |
|         .with_function("parallel", |b, n| {
 | |
|             let data = data(*n);
 | |
|             let mut world = setup(&data);
 | |
|             join(|| {}, || b.iter(|| parallel(&mut world)));
 | |
|         })
 | |
|         .with_function("par_for_each_mut", |b, n| {
 | |
|             let data = data(*n);
 | |
|             let mut world = setup(&data);
 | |
|             join(|| {}, || b.iter(|| par_for_each_mut(&mut world)));
 | |
|         }),
 | |
|     );
 | |
| }
 | |
| 
 | |
| criterion_group!(iterate, bench_ordered);
 | |
| criterion_main!(iterate);
 | 
