Infra for "unit" benchmarking
This commit is contained in:
parent
9ea2c96ddd
commit
4b1279d0b1
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1640,6 +1640,7 @@ name = "test_utils"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"dissimilar",
|
||||
"profile",
|
||||
"rustc-hash",
|
||||
"serde_json",
|
||||
"stdx",
|
||||
|
@ -1,7 +1,5 @@
|
||||
use std::fs;
|
||||
|
||||
use expect_test::expect;
|
||||
use test_utils::project_dir;
|
||||
use test_utils::{bench, bench_fixture, skip_slow_tests};
|
||||
|
||||
use super::{check_infer, check_types};
|
||||
|
||||
@ -617,12 +615,11 @@ fn main() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn include_accidentally_quadratic() {
|
||||
let file = project_dir().join("crates/syntax/test_data/accidentally_quadratic");
|
||||
let big_file = fs::read_to_string(file).unwrap();
|
||||
let big_file = vec![big_file; 10].join("\n");
|
||||
|
||||
fn benchmark_include_macro() {
|
||||
if skip_slow_tests() {
|
||||
return;
|
||||
}
|
||||
let data = bench_fixture::big_struct();
|
||||
let fixture = r#"
|
||||
//- /main.rs
|
||||
#[rustc_builtin_macro]
|
||||
@ -635,8 +632,12 @@ fn main() {
|
||||
//^ RegisterBlock
|
||||
}
|
||||
"#;
|
||||
let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file);
|
||||
let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data);
|
||||
|
||||
{
|
||||
let _b = bench("include macro");
|
||||
check_types(&fixture);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,7 +1,5 @@
|
||||
use std::fs;
|
||||
|
||||
use expect_test::{expect_file, ExpectFile};
|
||||
use test_utils::project_dir;
|
||||
use test_utils::{bench, bench_fixture, skip_slow_tests};
|
||||
|
||||
use crate::{fixture, FileRange, TextRange};
|
||||
|
||||
@ -228,15 +226,19 @@ fn bar() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accidentally_quadratic() {
|
||||
let file = project_dir().join("crates/syntax/test_data/accidentally_quadratic");
|
||||
let src = fs::read_to_string(file).unwrap();
|
||||
fn benchmark_syntax_highlighting() {
|
||||
if skip_slow_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let (analysis, file_id) = fixture::file(&src);
|
||||
let fixture = bench_fixture::big_struct();
|
||||
let (analysis, file_id) = fixture::file(&fixture);
|
||||
|
||||
// let t = std::time::Instant::now();
|
||||
let _ = analysis.highlight(file_id).unwrap();
|
||||
// eprintln!("elapsed: {:?}", t.elapsed());
|
||||
let hash = {
|
||||
let _pt = bench("syntax highlighting");
|
||||
analysis.highlight(file_id).unwrap().len()
|
||||
};
|
||||
assert_eq!(hash, 32009);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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" }
|
||||
|
28
crates/test_utils/src/bench_fixture.rs
Normal file
28
crates/test_utils/src/bench_fixture.rs
Normal file
@ -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
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
|
||||
#[macro_use]
|
||||
pub mod mark;
|
||||
pub mod bench_fixture;
|
||||
mod fixture;
|
||||
|
||||
use std::{
|
||||
@ -16,6 +17,7 @@
|
||||
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<dissimilar::Chunk>) -> 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 }
|
||||
}
|
||||
|
@ -397,6 +397,11 @@ There's no additional checks in CI, formatting and tidy tests are run with `carg
|
||||
|
||||
**Architecture Invariant:** tests do not depend on any kind of external resources, they are perfectly reproducible.
|
||||
|
||||
|
||||
### Performance Testing
|
||||
|
||||
TBA, take a look at the `metrics` xtask and `#[test] fn benchmark_xxx()` functions.
|
||||
|
||||
### Error Handling
|
||||
|
||||
**Architecture Invariant:** core parts of rust-analyzer (`ide`/`hir`) don't interact with the outside world and thus can't fail.
|
||||
|
Loading…
Reference in New Issue
Block a user