#![feature(test)] #![feature(bench_black_box)] #![cfg(not(tarpaulin_include))] extern crate rand; extern crate rand_pcg; extern crate test; use evalexpr::build_operator_tree; use rand::{distributions::Uniform, seq::SliceRandom, Rng, SeedableRng}; use rand_pcg::Pcg32; use std::hint::black_box; use test::Bencher; use std::fmt::Write; const BENCHMARK_LEN: usize = 100_000; const EXPONENTIAL_TUPLE_ITERATIONS: usize = 12; fn generate_expression(len: usize, gen: &mut Gen) -> String { let int_distribution = Uniform::new_inclusive(1, 100); let whitespaces = vec![" ", "", "", " ", " \n", " "]; let operators = vec!["+", "-", "*", "/", "%", "^"]; let mut result = String::new(); write!(result, "{}", gen.sample(int_distribution)).unwrap(); while result.len() < len { result.push_str(whitespaces.choose(gen).unwrap()); result.push_str(operators.choose(gen).unwrap()); result.push_str(whitespaces.choose(gen).unwrap()); write!(result, "{}", gen.sample(int_distribution)).unwrap(); } result } fn generate_expression_chain(len: usize, gen: &mut Gen) -> String { let mut chain = generate_expression(10, gen); while chain.len() < len { chain.push_str("; "); chain.push_str(&generate_expression(10, gen)); } chain } fn generate_small_expressions(len: usize, gen: &mut Gen) -> Vec { let mut result = Vec::new(); let mut result_len = 0; while result_len < len { let expression = generate_expression(10, gen); result_len += expression.len(); result.push(expression); } result } fn generate_large_tuple_expression(iterations: usize, gen: &mut Gen) -> String { let mut result = String::from("a=("); result.push_str(&generate_expression(0, gen)); result.push(','); result.push_str(&generate_expression(0, gen)); result.push(')'); for _ in 0..iterations { result.push_str(";a=(a,a)") } dbg!(result) } #[bench] fn bench_parse_long_expression_chains(bencher: &mut Bencher) { let mut gen = Pcg32::seed_from_u64(0); let long_expression_chain = generate_expression_chain(BENCHMARK_LEN, &mut gen); bencher.iter(|| build_operator_tree(&long_expression_chain).unwrap()); } #[bench] fn bench_parse_deep_expression_trees(bencher: &mut Bencher) { let mut gen = Pcg32::seed_from_u64(15); let deep_expression_tree = generate_expression(BENCHMARK_LEN, &mut gen); bencher.iter(|| build_operator_tree(&deep_expression_tree).unwrap()); } #[bench] fn bench_parse_many_small_expressions(bencher: &mut Bencher) { let mut gen = Pcg32::seed_from_u64(33); let small_expressions = generate_small_expressions(BENCHMARK_LEN, &mut gen); bencher.iter(|| { for expression in &small_expressions { black_box(build_operator_tree(expression).unwrap()); } }); } #[bench] fn bench_evaluate_long_expression_chains(bencher: &mut Bencher) { let mut gen = Pcg32::seed_from_u64(0); let long_expression_chain = build_operator_tree(&generate_expression_chain(BENCHMARK_LEN, &mut gen)).unwrap(); bencher.iter(|| long_expression_chain.eval().unwrap()); } #[bench] fn bench_evaluate_deep_expression_trees(bencher: &mut Bencher) { let mut gen = Pcg32::seed_from_u64(15); let deep_expression_tree = build_operator_tree(&generate_expression(BENCHMARK_LEN, &mut gen)).unwrap(); bencher.iter(|| deep_expression_tree.eval().unwrap()); } #[bench] fn bench_evaluate_many_small_expressions(bencher: &mut Bencher) { let mut gen = Pcg32::seed_from_u64(33); let small_expressions: Vec<_> = generate_small_expressions(BENCHMARK_LEN, &mut gen) .iter() .map(|expression| build_operator_tree(expression).unwrap()) .collect(); bencher.iter(|| { for expression in &small_expressions { black_box(expression.eval().unwrap()); } }); } #[bench] fn bench_evaluate_large_tuple_expression(bencher: &mut Bencher) { let mut gen = Pcg32::seed_from_u64(44); let large_tuple_expression = build_operator_tree(&generate_large_tuple_expression( EXPONENTIAL_TUPLE_ITERATIONS, &mut gen, )) .unwrap(); dbg!(&large_tuple_expression); bencher.iter(|| large_tuple_expression.eval().unwrap()); }