From 4b1279d0b160d98c1429ca1a52b37aa7a0af5775 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 9 Feb 2021 19:29:40 +0300 Subject: Infra for "unit" benchmarking --- crates/test_utils/Cargo.toml | 1 + crates/test_utils/src/bench_fixture.rs | 28 ++++++++++++++++++++++ crates/test_utils/src/lib.rs | 43 ++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 crates/test_utils/src/bench_fixture.rs (limited to 'crates/test_utils') diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml index 06341f003..2a65000b8 100644 --- a/crates/test_utils/Cargo.toml +++ b/crates/test_utils/Cargo.toml @@ -17,3 +17,4 @@ serde_json = "1.0.48" rustc-hash = "1.1.0" stdx = { path = "../stdx", version = "0.0.0" } +profile = { path = "../profile", version = "0.0.0" } diff --git a/crates/test_utils/src/bench_fixture.rs b/crates/test_utils/src/bench_fixture.rs new file mode 100644 index 000000000..41fcca635 --- /dev/null +++ b/crates/test_utils/src/bench_fixture.rs @@ -0,0 +1,28 @@ +//! Generates large snippets of Rust code for usage in the benchmarks. + +use stdx::format_to; + +pub fn big_struct() -> String { + let n = 1_000; + + let mut buf = "pub struct RegisterBlock {".to_string(); + for i in 0..n { + format_to!(buf, " /// Doc comment for {}.\n", i); + format_to!(buf, " pub s{}: S{},\n", i, i); + } + buf.push_str("}\n\n"); + for i in 0..n { + format_to!( + buf, + " + +#[repr(transparent)] +struct S{} {{ + field: u32, +}}", + i + ); + } + + buf +} diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index e19d2ad61..5be4a64fc 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -8,6 +8,7 @@ #[macro_use] pub mod mark; +pub mod bench_fixture; mod fixture; use std::{ @@ -16,6 +17,7 @@ use std::{ path::PathBuf, }; +use profile::StopWatch; use serde_json::Value; use stdx::lines_with_ends; use text_size::{TextRange, TextSize}; @@ -406,3 +408,44 @@ pub fn format_diff(chunks: Vec) -> String { } buf } + +/// Utility for writing benchmark tests. +/// +/// A benchmark test looks like this: +/// +/// ``` +/// #[test] +/// fn benchmark_foo() { +/// if skip_slow_tests() { return; } +/// +/// let data = bench_fixture::some_fixture(); +/// let analysis = some_setup(); +/// +/// let hash = { +/// let _b = bench("foo"); +/// actual_work(analysis) +/// }; +/// assert_eq!(hash, 92); +/// } +/// ``` +/// +/// * We skip benchmarks by default, to save time. +/// Ideal benchmark time is 800 -- 1500 ms in debug. +/// * We don't count preparation as part of the benchmark +/// * The benchmark itself returns some kind of numeric hash. +/// The hash is used as a sanity check that some code is actually run. +/// Otherwise, it's too easy to win the benchmark by just doing nothing. +pub fn bench(label: &'static str) -> impl Drop { + struct Bencher { + sw: StopWatch, + label: &'static str, + } + + impl Drop for Bencher { + fn drop(&mut self) { + eprintln!("{}: {}", self.label, self.sw.elapsed()) + } + } + + Bencher { sw: StopWatch::start(), label } +} -- cgit v1.2.3