Skip to content
Snippets Groups Projects
Commit 008f1cda authored by Dorian Weber's avatar Dorian Weber
Browse files

Improved the benchmark code and factored the SLX part into a module.

parent 89394b9c
No related merge requests found
use criterion::{Criterion, BenchmarkId, criterion_group, criterion_main, BatchSize, PlotConfiguration, AxisScale, SamplingMode}; use criterion::{Criterion, BenchmarkId, criterion_group, criterion_main,
use std::{process::Command, time::Duration}; BatchSize, PlotConfiguration, AxisScale, SamplingMode};
use itertools::Itertools;
const RANGE : u32 = 10; mod support;
const STEP : Time = 1000.0;
const SLX_PATH: &'static str = "C:/Wolverine/SLX/sse.exe";
const RANGE: u32 = 10;
const STEP: Time = 16000.0;
fn barbershop_bench(c: &mut Criterion) { fn barbershop_bench(c: &mut Criterion) {
let mut group = c.benchmark_group("Barbershop"); let mut group = c.benchmark_group("Barbershop");
// set-up the benchmark parameters
group.confidence_level(0.99); group.confidence_level(0.99);
group.plot_config( group.plot_config(
PlotConfiguration::default() PlotConfiguration::default()
...@@ -15,8 +18,8 @@ fn barbershop_bench(c: &mut Criterion) { ...@@ -15,8 +18,8 @@ fn barbershop_bench(c: &mut Criterion) {
); );
group.sampling_mode(SamplingMode::Linear); 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) { for sim_duration in (0..RANGE).map(|c| Time::from(1 << c)*STEP) {
// benchmark the SLX implementation
let duration = sim_duration.to_string(); let duration = sim_duration.to_string();
let args = [ let args = [
"/silent", "/silent",
...@@ -29,43 +32,19 @@ fn barbershop_bench(c: &mut Criterion) { ...@@ -29,43 +32,19 @@ fn barbershop_bench(c: &mut Criterion) {
duration.as_str() duration.as_str()
]; ];
group.measurement_time(Duration::from_secs(60)); // benchmark the SLX implementation
group.bench_function( group.bench_function(
BenchmarkId::new("SLX", sim_duration), BenchmarkId::new("SLX", sim_duration),
|b| b.iter_custom(|iters| { |b| b.iter_custom(|iters|
(0..iters) support::slx_bench(
.into_iter() SLX_PATH,
.chunks(3200000/(sim_duration as usize)) &args,
.into_iter() iters as usize
.map(|range| { ).expect("couldn't benchmark the SLX program")
let rc = Command::new("C:/Wolverine/SLX/sse.exe") )
.args(args.iter())
.arg(range.count().to_string())
.output()
.expect("failed to run the SLX program");
if !rc.status.success() {
panic!(match rc.status.code().unwrap() {
-10001 => "Unable to find a security key with SLX permission",
-10002 => "The command line includes an invalid option",
-10003 => "The source file cannot be found",
-10004 => "The specified/implied output file cannot be written",
-10005 => "The program contains compile-time errors",
-10006 => "The program has terminated with a run-time error",
-10007 => "The /genrts option failed",
_ => "Unknown error code"
})
}
Duration::from_secs_f64(
(&String::from_utf8_lossy(&rc.stdout)).trim().parse().unwrap()
)
}).sum()
})
); );
// benchmark the Rust implementation // benchmark the Rust implementation
group.measurement_time(Duration::from_secs(5));
group.bench_function( group.bench_function(
BenchmarkId::new("Rust", sim_duration), BenchmarkId::new("Rust", sim_duration),
|b| b.iter_batched( |b| b.iter_batched(
......
use criterion::{Criterion, BenchmarkId, criterion_group, criterion_main, BatchSize, PlotConfiguration, AxisScale, SamplingMode}; use criterion::{Criterion, BenchmarkId, criterion_group, criterion_main,
use std::{process::Command, time::Duration}; BatchSize, PlotConfiguration, AxisScale, SamplingMode};
use itertools::Itertools;
const SEED : u64 = 100000; mod support;
const RANGE : u32 = 10;
const STEP : Time = 1000.0; const SLX_PATH: &'static str = "C:/Wolverine/SLX/sse.exe";
const SEED: u64 = 100000;
const RANGE: u32 = 10;
const STEP: Time = 1000.0;
fn ferry_bench(c: &mut Criterion) { fn ferry_bench(c: &mut Criterion) {
let mut group = c.benchmark_group("Ferry"); let mut group = c.benchmark_group("Ferry");
// set-up the benchmark parameters
group.confidence_level(0.99); group.confidence_level(0.99);
group.plot_config( group.plot_config(
PlotConfiguration::default() PlotConfiguration::default()
...@@ -16,8 +19,8 @@ fn ferry_bench(c: &mut Criterion) { ...@@ -16,8 +19,8 @@ fn ferry_bench(c: &mut Criterion) {
); );
group.sampling_mode(SamplingMode::Linear); group.sampling_mode(SamplingMode::Linear);
// vary in the length of the simulation run
for (i, sim_duration) in (0..RANGE).map(|c| Time::from(1 << c)*STEP).enumerate() { for (i, sim_duration) in (0..RANGE).map(|c| Time::from(1 << c)*STEP).enumerate() {
// benchmark the SLX implementation
let duration = sim_duration.to_string(); let duration = sim_duration.to_string();
let args = [ let args = [
"/silent", "/silent",
...@@ -30,43 +33,19 @@ fn ferry_bench(c: &mut Criterion) { ...@@ -30,43 +33,19 @@ fn ferry_bench(c: &mut Criterion) {
duration.as_str() duration.as_str()
]; ];
group.measurement_time(Duration::from_secs(60)); // benchmark the SLX implementation
group.bench_function( group.bench_function(
BenchmarkId::new("SLX", sim_duration), BenchmarkId::new("SLX", sim_duration),
|b| b.iter_custom(|iters| { |b| b.iter_custom(|iters|
(0..iters) support::slx_bench(
.into_iter() SLX_PATH,
.chunks(620000/(sim_duration as usize)) &args,
.into_iter() iters as usize
.map(|range| { ).expect("couldn't benchmark the SLX program")
let rc = Command::new("C:/Wolverine/SLX/sse.exe") )
.args(args.iter())
.arg(range.count().to_string())
.output()
.expect("failed to run the SLX program");
if !rc.status.success() {
panic!(match rc.status.code().unwrap() {
-10001 => "Unable to find a security key with SLX permission",
-10002 => "The command line includes an invalid option",
-10003 => "The source file cannot be found",
-10004 => "The specified/implied output file cannot be written",
-10005 => "The program contains compile-time errors",
-10006 => "The program has terminated with a run-time error",
-10007 => "The /genrts option failed",
_ => "Unknown error code"
})
}
Duration::from_secs_f64(
(&String::from_utf8_lossy(&rc.stdout)).trim().parse().unwrap()
)
}).sum()
})
); );
// benchmark the Rust implementation // benchmark the Rust implementation
group.measurement_time(Duration::from_secs(5));
group.bench_function( group.bench_function(
BenchmarkId::new("Rust", sim_duration), BenchmarkId::new("Rust", sim_duration),
|b| b.iter_batched( |b| b.iter_batched(
......
use criterion::{Criterion, BenchmarkId, criterion_group, criterion_main, BatchSize, PlotConfiguration, AxisScale, SamplingMode}; use criterion::{Criterion, BenchmarkId, criterion_group, criterion_main,
use std::{process::Command, time::Duration}; PlotConfiguration, AxisScale, SamplingMode};
use itertools::Itertools;
const SEED : u64 = 100000; mod support;
const RANGE : u32 = 10;
const STEP : usize = 10; const SLX_PATH: &'static str = "C:/Wolverine/SLX/sse.exe";
const SEED: u64 = 100000;
const RANGE: u32 = 10;
const STEP: u64 = 10;
const PHILOSOPHER_COUNT: usize = 5; const PHILOSOPHER_COUNT: usize = 5;
fn philosopher_bench(c: &mut Criterion) { fn philosopher_bench(c: &mut Criterion) {
let mut group = c.benchmark_group("Philosophers"); let mut group = c.benchmark_group("Philosophers");
// benchmark the SLX implementation
group.confidence_level(0.99); group.confidence_level(0.99);
group.plot_config( group.plot_config(
PlotConfiguration::default() PlotConfiguration::default()
...@@ -17,8 +20,8 @@ fn philosopher_bench(c: &mut Criterion) { ...@@ -17,8 +20,8 @@ fn philosopher_bench(c: &mut Criterion) {
); );
group.sampling_mode(SamplingMode::Linear); group.sampling_mode(SamplingMode::Linear);
for (i, experiment_count) in (0..RANGE).map(|c| (1 << c)*STEP).enumerate() { // vary in the number of performed experiments
// benchmark the SLX implementation for experiment_count in (0..RANGE).map(|c| (1 << c)*STEP) {
let count = experiment_count.to_string(); let count = experiment_count.to_string();
let args = [ let args = [
"/silent", "/silent",
...@@ -31,46 +34,28 @@ fn philosopher_bench(c: &mut Criterion) { ...@@ -31,46 +34,28 @@ fn philosopher_bench(c: &mut Criterion) {
count.as_str() count.as_str()
]; ];
group.measurement_time(Duration::from_secs(60)); // benchmark the SLX implementation
group.bench_function( group.bench_function(
BenchmarkId::new("SLX", experiment_count), BenchmarkId::new("SLX", experiment_count),
|b| b.iter_custom(|iters| { |b| b.iter_custom(|iters|
let rc = Command::new("C:/Wolverine/SLX/sse.exe") support::slx_bench(
.args(args.iter()) SLX_PATH,
.arg(iters.to_string()) &args,
.output() iters as usize
.expect("failed to run the SLX program"); ).expect("couldn't benchmark the SLX program")
)
if !rc.status.success() {
panic!(match rc.status.code().unwrap() {
-10001 => "Unable to find a security key with SLX permission",
-10002 => "The command line includes an invalid option",
-10003 => "The source file cannot be found",
-10004 => "The specified/implied output file cannot be written",
-10005 => "The program contains compile-time errors",
-10006 => "The program has terminated with a run-time error",
-10007 => "The /genrts option failed",
_ => "Unknown error code"
})
}
Duration::from_secs_f64(
(&String::from_utf8_lossy(&rc.stdout)).trim().parse().unwrap()
)
})
); );
// benchmark the Rust implementation // benchmark the Rust implementation
group.measurement_time(Duration::from_secs(5));
group.bench_function( group.bench_function(
BenchmarkId::new("Rust", experiment_count), BenchmarkId::new("Rust", experiment_count),
|b| b.iter(|| (1..=experiment_count) |b| b.iter(|| (1..=experiment_count)
.into_par_iter() .into_par_iter()
.map(|j| .map(|experiment_no|
simulation( simulation(
// global data // global data
Shared { Shared {
master_rng: RefCell::new(SmallRng::seed_from_u64(SEED*(((i+1)*j) as u64))), master_rng: RefCell::new(SmallRng::seed_from_u64(SEED*experiment_no)),
sim_duration: Cell::default() sim_duration: Cell::default()
}, },
// simulation entry point // simulation entry point
......
use std::{process::Command, time::Duration, iter::once};
use itertools::Itertools;
/// Runs the SLX runtime environment once for an SLX program that measures its
/// own duration and returns it on the standard output.
///
/// Errors during this execution are returned back to the caller.
fn slx_run_once(program: &str, arguments: &[&str], iterations: usize) -> Result<Duration, (i32, String)> {
// start the SLX runtime and wait for its return
let rc = Command::new(program)
.args(arguments)
.arg(iterations.to_string())
.output()
.map_err(|err| (-1, format!("Failed to run the SLX program: {}", err)))?;
if !rc.status.success() {
// check the error code and add a description to it
Err(rc.status
.code()
.map_or_else(
|| (-10000, "Unknown error code".to_string()),
|code| {
(code, match code {
-10001 => "Unable to find a security key with SLX permission".to_string(),
-10002 => "The command line includes an invalid option".to_string(),
-10003 => "The source file cannot be found".to_string(),
-10004 => "The specified/implied output file cannot be written".to_string(),
-10005 => "The program contains compile-time errors".to_string(),
-10006 => "The program has terminated with a run-time error".to_string(),
-10007 => "The /genrts option failed".to_string(),
_ => format!("Unknown error code: {}", code)
})
}
)
)
} else {
Ok(Duration::from_secs_f64(
(&String::from_utf8_lossy(&rc.stdout)).trim().parse().unwrap()
))
}
}
/// Repeats runs of an SLX program for a specified number of times and collects
/// the total (real-time) duration of those combined runs.
///
/// The SLX program in question has to report its own real-time duration using
/// the standard output.
pub fn slx_bench(program: &str, arguments: &[&str], iterations: usize) -> Result<Duration, String> {
// try to complete the iterations in a single run of the SLX program
slx_run_once(program, arguments, iterations)
.or_else(|(code, desc)| {
if code == -10006 {
// Runtime error: this happens when the free version of SLX
// exceeds its total instance budget, either through a
// complicated scenario or too many iterations in one call.
// We can still make this work by running SLX multiple times
// with lower iteration counts and combining the timings.
// This effectively trades benchmark speed with simulation model
// size.
(1..)
.map(|i| iterations >> i)
.take_while(|&chunk_size| chunk_size > 0)
// .inspect(|chunk_size| println!("reducing the chunk size to {}", chunk_size))
.map(|chunk_size| {
(0..(iterations - 1)/chunk_size)
.map(|_| chunk_size)
.chain(once((iterations - 1) % chunk_size + 1))
.map(|size|
slx_run_once(program, arguments, size)
)
.fold_ok(Duration::default(), |duration, run| duration + run)
})
.find_map(|result| result.ok())
.ok_or(desc)
} else {
Err(desc)
}
})
}
import <h7> import <h7>
// enable this macro for the benchmark // enable this macro for the benchmark
#define BENCH // #define BENCH
module barbershop { module barbershop {
// globally shared data // globally shared data
......
use simcore_rs::{channel, simulation};
fn main() { fn main() {
simulation( let iterations = 11;
(), let chunk_size = 4;
|sim| sim.process(async move {
println!("[{}] Begin", sim.now()); let res: Vec<_> = (0..(iterations - 1)/chunk_size)
.map(|_| chunk_size)
let (sx, rx) = channel(); .chain(std::iter::once((iterations - 1) % chunk_size + 1))
sim.activate(async move { .collect();
for i in 0.. {
sim.advance(1.0).await; println!("{:?}", res);
sx.send(i).await.ok();
}
});
sim.select(async move {
while let Some(i) = rx.recv().await {
println!("[{}] Received {}", sim.now(), i);
if i >= 3 { break; }
}
println!("[{}] Exit Receiver Process", sim.now());
}, sim.advance(5.0)).await;
sim.advance(10.0).await;
println!("[{}] End", sim.now());
})
);
} }
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment