diff --git a/.gitignore b/.gitignore index ea8c4bf7f35f6f77f75d92ad8ce8349f6e81ddba..30be2fc50c295ed846c5773a106a0cd77cdf8742 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /target +/.idea/ +/uml/ diff --git a/benches/barbershop.rs b/benches/barbershop.rs new file mode 100644 index 0000000000000000000000000000000000000000..a8ab06fd9727a13bc90ecd91980ff4f48a11762c --- /dev/null +++ b/benches/barbershop.rs @@ -0,0 +1,99 @@ +use simcore_rs::{Time, SimContext, Facility, simulation}; +use rand::{distributions::Uniform, rngs::SmallRng, SeedableRng, Rng}; +use criterion::{Criterion, BenchmarkId, criterion_group, criterion_main, BatchSize}; +use std::time::Duration; + +const SEED_A : u64 = 100000; +const SEED_S : u64 = 200000; +const RANGE : u32 = 8; +const STEP : Time = 100000.0; + +fn barbershop(c: &mut Criterion) { + let mut group = c.benchmark_group("Barbershop"); + let mut rng_a = SmallRng::seed_from_u64(SEED_A); + let mut rng_s = SmallRng::seed_from_u64(SEED_S); + + group.measurement_time(Duration::from_secs_f64(30.0)); + group.confidence_level(0.99); + + for stop_time in (1..=RANGE).map(|c| Time::from(c)*STEP) { + group.bench_with_input( + BenchmarkId::from_parameter(stop_time), + &stop_time, + |b, &stop_time| + b.iter_batched( + || { + (SmallRng::from_rng(&mut rng_a).unwrap(), + SmallRng::from_rng(&mut rng_s).unwrap()) + }, + |(rng_a, rng_s)| { + let shop = BarberShop { + stop_time, rng_a, rng_s, joe: &Facility::new() + }; + + simulation(|sim| shop.actions(sim)); + }, + BatchSize::SmallInput + ) + ); + } + + group.finish(); +} + +criterion_group!(benches, barbershop); +criterion_main!(benches); + +/* *************************** Barbershop Example *************************** */ + +/// Barbershop process. +struct BarberShop<'j> { + stop_time: Time, rng_a: SmallRng, rng_s: SmallRng, joe: &'j Facility +} + +impl<'j> BarberShop<'j> { + async fn actions(self, sim: SimContext<'j>) { + // unpack the barber shop structure for easier access + let Self { + stop_time, mut rng_a, mut rng_s, joe + } = self; + + // activate a process to generate the customers + sim.activate(async move { + let dist = Uniform::new(12.0, 24.0); + + // wait some time before activating the first customer + sim.advance(rng_a.sample(dist)).await; + + // generate new customers until the store closes officially + while sim.now() < stop_time { + // activate the next customer + sim.activate(Customer { + joe, rng: SmallRng::from_seed(rng_s.gen()) + }.actions(sim)); + // wait some time before activating the next customer + sim.advance(rng_a.sample(dist)).await; + } + }); + + // wait until the store closes + sim.advance(self.stop_time).await; + + // finish processing the queue (no more customers arrive) + joe.seize().await; + } +} + +/// Customer process with access to the barber and a random number generator. +struct Customer<'j> { joe: &'j Facility, rng: SmallRng } + +impl Customer<'_> { + pub async fn actions(mut self, sim: SimContext<'_>) { + // access the barber + self.joe.seize().await; + // spend time + sim.advance(self.rng.gen_range(12.0, 18.0)).await; + // release the barber + self.joe.release(); + } +}