diff --git a/Cargo.lock b/Cargo.lock index 01de430925dc..6eae6a87628f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,12 +17,33 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "allocator-api2" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + [[package]] name = "anyhow" version = "1.0.97" @@ -119,6 +140,12 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66bb12751a83493ef4b8da1120451a262554e216a247f14b48cb5e8fe7ed8bdf" +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + [[package]] name = "camino" version = "1.1.9" @@ -151,6 +178,12 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.2.16" @@ -239,6 +272,58 @@ dependencies = [ "tracing", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + [[package]] name = "countme" version = "3.0.1" @@ -260,6 +345,42 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -303,6 +424,12 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + [[package]] name = "ctrlc" version = "3.4.7" @@ -516,6 +643,16 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -554,6 +691,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" + [[package]] name = "hir" version = "0.0.0" @@ -661,6 +804,7 @@ dependencies = [ "chalk-recursive", "chalk-solve", "cov-mark", + "criterion", "either", "ena", "expect-test", @@ -1025,6 +1169,26 @@ dependencies = [ "triomphe", ] +[[package]] +name = "is-terminal" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +dependencies = [ + "hermit-abi 0.5.1", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -1055,6 +1219,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a037eddb7d28de1d0fc42411f501b53b75838d313908078d6698d064f3029b24" +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "kqueue" version = "1.0.8" @@ -1368,13 +1542,22 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] @@ -1504,6 +1687,34 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "portable-atomic" version = "1.11.0" @@ -1801,6 +2012,35 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "rowan" version = "0.15.15" @@ -1919,6 +2159,12 @@ dependencies = [ "smallvec", ] +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + [[package]] name = "ryu" version = "1.0.20" @@ -2352,6 +2598,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "toml" version = "0.8.20" @@ -2590,6 +2846,74 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi-util" version = "0.1.9" diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index efa544cf3965..15b22e59407a 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -56,6 +56,7 @@ tracing.workspace = true tracing-subscriber.workspace = true tracing-tree.workspace = true project-model.workspace = true +criterion = "0.5" # local deps test-utils.workspace = true @@ -64,5 +65,9 @@ test-fixture.workspace = true [features] in-rust-tree = ["hir-expand/in-rust-tree"] +[[bench]] +name = "incremental" +harness = false + [lints] workspace = true diff --git a/crates/hir-ty/benches/incremental.rs b/crates/hir-ty/benches/incremental.rs new file mode 100644 index 000000000000..1e3f16a6d4ff --- /dev/null +++ b/crates/hir-ty/benches/incremental.rs @@ -0,0 +1,212 @@ +use base_db::{ + CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, RootQueryDb, SourceDatabase, + SourceRoot, SourceRootId, SourceRootInput, +}; +use criterion::{Criterion, black_box, criterion_group, criterion_main}; +use hir_def::{ModuleId, db::DefDatabase, nameres::crate_def_map}; +use hir_ty::db::HirDatabase; +use salsa::Durability; +use span::FileId; +use std::{fmt, panic}; +use test_fixture::WithFixture; +use triomphe::Arc; + +#[salsa_macros::db] +#[derive(Clone)] +pub(crate) struct BenchmarkDB { + storage: salsa::Storage, + files: Arc, + crates_map: Arc, +} + +impl Default for BenchmarkDB { + fn default() -> Self { + let mut this = Self { + storage: salsa::Storage::new(None), + files: Default::default(), + crates_map: Default::default(), + }; + this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH); + // This needs to be here otherwise `CrateGraphBuilder` panics. + this.set_all_crates(Arc::new(Box::new([]))); + CrateGraphBuilder::default().set_in_db(&mut this); + this + } +} + +impl fmt::Debug for BenchmarkDB { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TestDB").finish() + } +} + +#[salsa_macros::db] +impl SourceDatabase for BenchmarkDB { + fn file_text(&self, file_id: base_db::FileId) -> FileText { + self.files.file_text(file_id) + } + + fn set_file_text(&mut self, file_id: base_db::FileId, text: &str) { + let files = Arc::clone(&self.files); + files.set_file_text(self, file_id, text); + } + + fn set_file_text_with_durability( + &mut self, + file_id: base_db::FileId, + text: &str, + durability: Durability, + ) { + let files = Arc::clone(&self.files); + files.set_file_text_with_durability(self, file_id, text, durability); + } + + /// Source root of the file. + fn source_root(&self, source_root_id: SourceRootId) -> SourceRootInput { + self.files.source_root(source_root_id) + } + + fn set_source_root_with_durability( + &mut self, + source_root_id: SourceRootId, + source_root: Arc, + durability: Durability, + ) { + let files = Arc::clone(&self.files); + files.set_source_root_with_durability(self, source_root_id, source_root, durability); + } + + fn file_source_root(&self, id: base_db::FileId) -> FileSourceRootInput { + self.files.file_source_root(id) + } + + fn set_file_source_root_with_durability( + &mut self, + id: base_db::FileId, + source_root_id: SourceRootId, + durability: Durability, + ) { + let files = Arc::clone(&self.files); + files.set_file_source_root_with_durability(self, id, source_root_id, durability); + } + + fn crates_map(&self) -> Arc { + self.crates_map.clone() + } +} + +#[salsa_macros::db] +impl salsa::Database for BenchmarkDB {} + +impl panic::RefUnwindSafe for BenchmarkDB {} + +impl BenchmarkDB { + pub(crate) fn module_for_file_opt(&self, file_id: impl Into) -> Option { + let file_id = file_id.into(); + for &krate in self.relevant_crates(file_id).iter() { + let crate_def_map = crate_def_map(self, krate); + for (local_id, data) in crate_def_map.modules() { + if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) { + return Some(crate_def_map.module_id(local_id)); + } + } + } + None + } + + pub(crate) fn module_for_file(&self, file_id: impl Into) -> ModuleId { + self.module_for_file_opt(file_id.into()).unwrap() + } +} + +fn benchmark_incremental_use_expr_addition(c: &mut Criterion) { + c.bench_function("incremental_use_expr_addition", |b| { + b.iter_batched( + || { + let (db, pos) = BenchmarkDB::with_position( + " +//- /lib.rs +fn foo() -> i32 { + $01 + 1 +}", + ); + + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + db.trait_impls_in_crate(module.krate()); + + (db, pos) + }, + |(mut db, pos)| { + let new_text = " +use std::collections::HashMap; + +fn foo() -> i32 { + $01 + 1 +}"; + + db.set_file_text(pos.file_id.file_id(&db), new_text); + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + + black_box(db.trait_impls_in_crate(module.krate())); + }, + criterion::BatchSize::LargeInput, + ); + }); +} + +fn benchmark_incremental_struct_addition(c: &mut Criterion) { + c.bench_function("incremental_struct_addition", |b| { + b.iter_batched( + || { + let (db, pos) = BenchmarkDB::with_position( + " +//- /lib.rs +fn foo() -> i32 { + 1 + 1 +} + +fn bar() -> f32 { + 2.0 * 3.0 +}$0", + ); + + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + db.trait_impls_in_crate(module.krate()); + + (db, pos) + }, + |(mut db, pos)| { + let new_text = " +//- /lib.rs +fn foo() -> i32 { + 1 + 1 +} + +fn bar() -> f32 { + 2.0 * 3.0 +} + +pub struct SomeStruct { + field: i32, +}$0"; + + db.set_file_text(pos.file_id.file_id(&db), new_text); + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + + black_box(db.trait_impls_in_crate(module.krate())); + }, + criterion::BatchSize::LargeInput, + ); + }); +} + +criterion_group!( + benches, + benchmark_incremental_use_expr_addition, + benchmark_incremental_struct_addition +); +criterion_main!(benches);