Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
barbershop.rs 3.13 KiB
use criterion::{Criterion, BenchmarkId, criterion_group, criterion_main,
                BatchSize, PlotConfiguration, AxisScale, SamplingMode};

mod support;

const SLX_PATH: &'static str = "C:/Wolverine/SLX/sse.exe";
const RANGE: u32 =   10;
const STEP: Time = 1000.0;

fn barbershop_bench(c: &mut Criterion) {
	let mut group = c.benchmark_group("Barbershop");
	
	// set-up the benchmark parameters
	group.confidence_level(0.99);
	group.plot_config(
		PlotConfiguration::default()
			.summary_scale(AxisScale::Logarithmic)
	);
	group.sampling_mode(SamplingMode::Linear);
	
	// vary in the length of the simulation run
	for sim_duration in (0..RANGE).map(|c| Time::from(1 << c)*STEP) {
		let duration = sim_duration.to_string();
		let args = [
			"/silent",
			"/stdout",
			"/noicon",
			"/nowarn",
			"/noxwarn",
			"/#BENCH",
			"slx\\barbershop.slx",
			duration.as_str()
		];
		
		// benchmark the SLX implementation
		group.bench_function(
			BenchmarkId::new("SLX", sim_duration),
			|b| b.iter_custom(|iters|
				support::slx_bench(
					SLX_PATH, 
					&args, 
					iters as usize
				).expect("couldn't benchmark the SLX program")
			)
		);
		
		// benchmark the Rust implementation
		group.bench_function(
			BenchmarkId::new("Rust", sim_duration),
			|b| b.iter_batched(
				|| Shared { joe: Facility::new(), wait_time: RandomVar::new() },
				|shared| simulation(
					shared,
					|sim| sim.process(barbershop(sim, sim_duration))
				),
				BatchSize::SmallInput
			)
		);
	}
	
	group.finish();
}

criterion_group!(benches, barbershop_bench);
criterion_main!(benches);

/* *************************** Barbershop Example *************************** */
use simcore_rs::{Time, SimContext, Facility, RandomVar, simulation};
use rand::{distributions::Uniform, rngs::SmallRng, SeedableRng, Rng};
/// Globally shared data.
struct Shared {
	joe: Facility,
	wait_time: RandomVar
}

// helper constants
const SEED_A      :  u64 = 100000;
const SEED_S      :  u64 = 200000;

/// Customer process with access to the barber and a random processing delay.
struct Customer { delay: Time }

impl Customer {
	pub async fn actions(self, sim: SimContext<'_,Shared>) {
		// access the barber and record the time for the report
		let arrival_time = sim.now();
		sim.shared().joe.seize().await;
		sim.shared().wait_time.tabulate(sim.now() - arrival_time);
		
		// spend time
		sim.advance(self.delay).await;
		// release the barber
		sim.shared().joe.release();
	}
}

async fn barbershop(sim: SimContext<'_,Shared>, duration: Time) {
	// pseudo random number generators referenced from within the main process
	let mut rng_a = SmallRng::seed_from_u64(SEED_A);
	let mut rng_s = SmallRng::seed_from_u64(SEED_S);
	
	// activate a process to generate the customers
	sim.activate(async move {
		let dist_a = Uniform::new(12.0, 24.0);
		let dist_s = Uniform::new(12.0, 18.0);
		loop {
			sim.advance(rng_a.sample(dist_a)).await;
			if sim.now() >= duration { return; }
			sim.activate(Customer {
				delay: rng_s.sample(dist_s)
			}.actions(sim));
		}
	});
	
	// wait until the store closes
	sim.advance(duration).await;
	
	// finish processing the queue (no more customers arrive)
	sim.shared().joe.seize().await;
}