diff --git a/chorus_lib/Cargo.toml b/chorus_lib/Cargo.toml index 560c75c..ad36aaf 100644 --- a/chorus_lib/Cargo.toml +++ b/chorus_lib/Cargo.toml @@ -22,6 +22,15 @@ ureq = "2.7.1" [dev-dependencies] chrono = { version = "0.4.26", features = ["serde"] } +criterion = { version = "0.5.1", features = ["html_reports"] } clap = { version = "4.3.21", features = ["derive"] } rand = "0.8.5" termcolor = "1.2.0" + +[[bench]] +name = "locally_benchmark" +harness = false + +[[bench]] +name = "comm_benchmark" +harness = false diff --git a/chorus_lib/benches/comm_benchmark.rs b/chorus_lib/benches/comm_benchmark.rs new file mode 100644 index 0000000..d70b7b9 --- /dev/null +++ b/chorus_lib/benches/comm_benchmark.rs @@ -0,0 +1,111 @@ +use chorus_lib::core::{ + ChoreoOp, Choreography, ChoreographyLocation, LocationSet, Projector, Transport, +}; +use chorus_lib::transport::local::{LocalTransport, LocalTransportChannelBuilder}; +use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; +use std::thread::spawn; + +#[derive(ChoreographyLocation)] +struct Alice; + +#[derive(ChoreographyLocation)] +struct Bob; + +struct CommChoreography { + n: u64, +} + +impl Choreography for CommChoreography { + type L = LocationSet!(Alice, Bob); + + fn run(self, op: &impl ChoreoOp) { + for _ in 0..self.n { + op.comm(Bob, Alice, &op.locally::(Bob, |_| 1.0)); + } + } +} + +fn comm_choreography(n: u64) { + let channel = LocalTransportChannelBuilder::new() + .with(Alice) + .with(Bob) + .build(); + let mut handles = Vec::new(); + { + let channel = channel.clone(); + handles.push(spawn(move || { + let transport = LocalTransport::new(Alice, channel); + let projector = Projector::new(Alice, transport); + let c = CommChoreography { n }; + projector.epp_and_run(c); + })); + } + { + let channel = channel.clone(); + handles.push(spawn(move || { + let transport = LocalTransport::new(Bob, channel); + let projector = Projector::new(Bob, transport); + let c = CommChoreography { n }; + projector.epp_and_run(c); + })); + } + for handle in handles { + handle.join().unwrap(); + } +} + +fn comm_handwritten_alice(n: u64, transport: &LocalTransport) { + for _ in 0..n { + transport.receive::(Bob::name(), Alice::name()); + } +} + +fn comm_handwritten_bob(n: u64, transport: &LocalTransport) { + for _ in 0..n { + transport.send::(Bob::name(), Alice::name(), &1.0); + } +} + +fn comm_handwritten(n: u64) { + let channel = LocalTransportChannelBuilder::new() + .with(Alice) + .with(Bob) + .build(); + let mut handles = Vec::new(); + { + let channel = channel.clone(); + handles.push(spawn(move || { + let transport = LocalTransport::new(Alice, channel); + comm_handwritten_alice(n, &transport); + })); + } + { + let channel = channel.clone(); + handles.push(spawn(move || { + let transport = LocalTransport::new(Bob, channel); + comm_handwritten_bob(n, &transport); + })); + } + for handle in handles { + handle.join().unwrap(); + } +} + +fn bench_comm(c: &mut Criterion) { + let mut group = c.benchmark_group("Comm"); + let range = [2000, 4000, 6000, 8000, 10000]; + for i in range.iter() { + group.bench_with_input(BenchmarkId::new("Handwritten", i), i, |b, i| { + b.iter(|| comm_handwritten(black_box(*i))) + }); + } + for i in range.iter() { + group.bench_with_input(BenchmarkId::new("Choreographic", i), i, |b, i| { + b.iter(|| comm_choreography(black_box(*i))) + }); + } + group.finish(); +} + +criterion_group!(benches, bench_comm); +criterion_main!(benches); diff --git a/chorus_lib/benches/locally_benchmark.rs b/chorus_lib/benches/locally_benchmark.rs new file mode 100644 index 0000000..b686352 --- /dev/null +++ b/chorus_lib/benches/locally_benchmark.rs @@ -0,0 +1,59 @@ +use chorus_lib::core::{ChoreoOp, Choreography, ChoreographyLocation, Located, LocationSet}; +use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; + +#[derive(ChoreographyLocation)] +struct Alice; + +struct AddToNLocallyChoreography { + n: f64, +} +impl Choreography> for AddToNLocallyChoreography { + type L = LocationSet!(Alice); + + fn run(self, op: &impl ChoreoOp) -> Located { + let mut i = op.locally(Alice, |_| 0.0); + for _ in 0..self.n.ceil() as u64 { + i = op.locally(Alice, |un| *un.unwrap(&i) + 1.0); + } + return i; + } +} + +fn add_to_n_locally_choreographic(n: f64) { + let c = AddToNLocallyChoreography { n }; + let channel = chorus_lib::transport::local::LocalTransportChannelBuilder::new() + .with(Alice) + .build(); + let transport = chorus_lib::transport::local::LocalTransport::new(Alice, channel); + let projector = chorus_lib::core::Projector::new(Alice, transport); + let result = projector.epp_and_run(c); + assert_eq!(projector.unwrap(result), n); +} + +fn add_to_n_locally_handwritten(n: f64) { + let mut a: f64 = 0.0; + for _ in 0..n.ceil() as u64 { + a += 1.0; + } + assert_eq!(a, n); +} + +fn bench_add_to_n_locally(c: &mut Criterion) { + let mut group = c.benchmark_group("Locally"); + let range = [2000, 4000, 6000, 8000, 10000]; + for i in range.iter() { + group.bench_with_input(BenchmarkId::new("Handwritten", i), i, |b, i| { + b.iter(|| add_to_n_locally_handwritten(black_box(*i as f64))) + }); + } + for i in range.iter() { + group.bench_with_input(BenchmarkId::new("Choreographic", i), i, |b, i| { + b.iter(|| add_to_n_locally_choreographic(black_box(*i as f64))) + }); + } + + group.finish(); +} + +criterion_group!(benches, bench_add_to_n_locally); +criterion_main!(benches);