Skip to content

Commit

Permalink
Divan benchmarking PoC (#140)
Browse files Browse the repository at this point in the history
* Divan benchmarking PoC

* Apply suggestions from @nvzqz

* different random polish calculator walks

* Update benches/divan.rs

Co-authored-by: Nikolai Vazquez <hello@nikolaivazquez.com>

* Update benches/divan.rs

Co-authored-by: Nikolai Vazquez <hello@nikolaivazquez.com>

* fmt

* divan::black_box_drop

* tidy up

* tidy up

---------

Co-authored-by: Nikolai Vazquez <hello@nikolaivazquez.com>
  • Loading branch information
CrockAgile and nvzqz committed Dec 13, 2023
1 parent 86c441a commit c5e3a5b
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 26 deletions.
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ features = ["derive"]
version = "1.0.61"

[dev-dependencies]
divan = "0.1.5"
insta = { version = "1.26.0", default-features = false }

[dev-dependencies.quickcheck]
Expand All @@ -49,7 +50,11 @@ unstable = []
tracing = ["dep:tracing", "dep:tracing-subscriber", "dep:tracing-flame"]

[[bench]]
name = "bnf"
name = "criterion"
harness = false

[[bench]]
name = "divan"
harness = false

[target.'cfg(target_arch = "wasm32")'.dependencies]
Expand Down
2 changes: 1 addition & 1 deletion benches/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ These benchmarks are not run during continuous integration testing. But if a dev

#### Flamegraph

> CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph --bench bnf -- --bench
> CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph --bench divan -- --bench
`sudo` may be required for `dtrace` on macOS

Expand Down
27 changes: 3 additions & 24 deletions benches/bnf.rs → benches/criterion.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,11 @@
mod util;

use bnf::Grammar;
use criterion::{criterion_group, criterion_main, Criterion};
use rand::seq::SliceRandom;

#[cfg(feature = "tracing")]
fn init_tracing() -> impl Drop {
use tracing_flame::FlameLayer;
use tracing_subscriber::{fmt, prelude::*};
let filter_layer = tracing_subscriber::EnvFilter::from_default_env();
let fmt_layer = fmt::Layer::default();
let (flame_layer, _guard) = FlameLayer::with_file("./tracing.folded").unwrap();

tracing_subscriber::registry()
.with(filter_layer)
.with(fmt_layer)
.with(flame_layer)
.init();

_guard
}

#[cfg(not(feature = "tracing"))]
fn init_tracing() {}

fn examples(c: &mut Criterion) {
init_tracing();

#[cfg(feature = "tracing")]
let _span = tracing::span!(tracing::Level::DEBUG, "BENCH EXAMPLES").entered();
let _tracing = util::init_tracing();

c.bench_function("parse postal", |b| {
let input = std::include_str!("../tests/fixtures/postal_address.terminated.input.bnf");
Expand Down
90 changes: 90 additions & 0 deletions benches/divan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
mod util;

fn main() {
let _tracing = util::init_tracing();

#[cfg(feature = "tracing")]
let _span = tracing::span!(tracing::Level::DEBUG, "BENCH EXAMPLES").entered();

divan::main();
}

mod examples {
#[divan::bench(min_time = 5, max_time = 60)]
fn parse_postal(bencher: divan::Bencher) {
let input = divan::black_box(include_str!(
"../tests/fixtures/postal_address.terminated.input.bnf"
));

bencher.bench(|| {
input.parse::<bnf::Grammar>().unwrap();
});
}

#[divan::bench(min_time = 5, max_time = 60)]
fn generate_dna(bencher: divan::Bencher) {
bencher
.with_inputs(|| {
let input = "<dna> ::= <base> | <base> <dna>
<base> ::= 'A' | 'C' | 'G' | 'T'";
let grammar: bnf::Grammar = input.parse().unwrap();
grammar
})
.bench_refs(|grammar| {
grammar.generate().unwrap();
});
}

#[divan::bench(min_time = 5, max_time = 60)]
fn parse_polish_calculator(bencher: divan::Bencher) {
let polish_calc_grammar: bnf::Grammar = "<product> ::= <number> | <op> <product> <product>
<op> ::= '+' | '-' | '*' | '/'
<number> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
"
.parse()
.unwrap();

// use pseudo random for consistent metrics
use rand::seq::SliceRandom;
let mut rng: rand::rngs::StdRng = rand::SeedableRng::seed_from_u64(0);
let random_walk_count = 100usize;
let mut random_walks: Vec<_> = (0..random_walk_count)
.map(|_| polish_calc_grammar.generate_seeded(&mut rng).unwrap())
.collect();

random_walks.shuffle(&mut rng);
let random_walks = divan::black_box(random_walks);
let mut index = (0..random_walk_count).cycle();

bencher.bench_local(|| {
let index = index.next().unwrap();
let input = &random_walks[index];
polish_calc_grammar
.parse_input(input)
.for_each(divan::black_box_drop);
});
}

#[divan::bench(min_time = 5, max_time = 60)]
fn parse_infinite_nullable_grammar(bencher: divan::Bencher) {
use rand::Rng;

let infinite_grammar: bnf::Grammar = "
<a> ::= '' | <b>
<b> ::= <a>"
.parse()
.unwrap();

let mut rng: rand::rngs::StdRng = rand::SeedableRng::seed_from_u64(0);

bencher
.with_inputs(|| rng.gen_range(1..100))
.count_inputs_as::<divan::counter::ItemsCount>()
.bench_local_values(|parse_count| {
infinite_grammar
.parse_input("")
.take(parse_count)
.for_each(divan::black_box_drop);
});
}
}
19 changes: 19 additions & 0 deletions benches/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#[cfg(feature = "tracing")]
pub fn init_tracing() -> impl Drop {
use tracing_flame::FlameLayer;
use tracing_subscriber::{fmt, prelude::*};
let filter_layer = tracing_subscriber::EnvFilter::from_default_env();
let fmt_layer = fmt::Layer::default();
let (flame_layer, _guard) = FlameLayer::with_file("./tracing.folded").unwrap();

tracing_subscriber::registry()
.with(filter_layer)
.with(fmt_layer)
.with(flame_layer)
.init();

_guard
}

#[cfg(not(feature = "tracing"))]
pub fn init_tracing() {}

0 comments on commit c5e3a5b

Please sign in to comment.