From e5c5c0a040e0c74892ea0a36c7fd50e5410879bd Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 21 Jan 2021 19:04:50 +0300 Subject: Include `countme` crate to count important data structures. --- Cargo.lock | 27 ++++++++++++++++++++++++-- crates/hir_def/src/item_tree.rs | 10 +++++++++- crates/hir_def/src/nameres.rs | 3 +++ crates/ide/src/status.rs | 2 ++ crates/profile/Cargo.toml | 1 + crates/profile/src/hprof.rs | 4 +++- crates/profile/src/lib.rs | 7 +++++++ crates/rust-analyzer/src/cli/analysis_stats.rs | 5 +++++ docs/dev/README.md | 3 +++ 9 files changed, 58 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71223218d..9f7a1d019 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,6 +273,17 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" +[[package]] +name = "countme" +version = "2.0.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5716604cba7c02a846ecad3f4a3fd2d2b641faccc2a24a51efb21aff0d01f35" +dependencies = [ + "dashmap", + "once_cell", + "rustc-hash", +] + [[package]] name = "crc32fast" version = "1.2.1" @@ -349,6 +360,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if 1.0.0", + "num_cpus", +] + [[package]] name = "dissimilar" version = "1.0.2" @@ -1260,6 +1281,7 @@ name = "profile" version = "0.0.0" dependencies = [ "cfg-if 1.0.0", + "countme", "jemalloc-ctl", "la-arena", "libc", @@ -1375,10 +1397,11 @@ checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" [[package]] name = "rowan" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea4527c692099becd37ec777cfd6949d0534348528d2fc84ee420d2d5fac83d" +checksum = "24c2d78254049413f9d73495f883e7fa0b7a7d4b88468cd72a3bbbd0ad585cd1" dependencies = [ + "countme", "hashbrown", "memoffset", "rustc-hash", diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 1226d7d85..b8d7608e7 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs @@ -21,6 +21,7 @@ use hir_expand::{ HirFileId, InFile, }; use la_arena::{Arena, Idx, RawIdx}; +use profile::Count; use rustc_hash::FxHashMap; use smallvec::SmallVec; use syntax::{ast, match_ast}; @@ -67,6 +68,8 @@ impl GenericParamsId { /// The item tree of a source file. #[derive(Debug, Eq, PartialEq)] pub struct ItemTree { + _c: Count, + top_level: SmallVec<[ModItem; 1]>, attrs: FxHashMap, @@ -116,7 +119,12 @@ impl ItemTree { } fn empty() -> Self { - Self { top_level: Default::default(), attrs: Default::default(), data: Default::default() } + Self { + _c: Count::new(), + top_level: Default::default(), + attrs: Default::default(), + data: Default::default(), + } } fn shrink_to_fit(&mut self) { diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 93931a21a..bd3ea9b8b 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs @@ -59,6 +59,7 @@ use std::sync::Arc; use base_db::{CrateId, Edition, FileId}; use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile}; use la_arena::Arena; +use profile::Count; use rustc_hash::FxHashMap; use stdx::format_to; use syntax::{ast, AstNode}; @@ -75,6 +76,7 @@ use crate::{ /// Contains all top-level defs from a macro-expanded crate #[derive(Debug, PartialEq, Eq)] pub struct DefMap { + _c: Count, parent: Option>, root: LocalModuleId, modules: Arena, @@ -215,6 +217,7 @@ impl DefMap { let mut modules: Arena = Arena::default(); let root = modules.alloc(ModuleData::default()); DefMap { + _c: Count::new(), parent: None, krate, edition, diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index e10d7c3a4..137c38c0d 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs @@ -38,6 +38,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { format_to!(buf, "{}\n", syntax_tree_stats(db)); format_to!(buf, "{} (macros)\n", macro_syntax_tree_stats(db)); format_to!(buf, "{} total\n", memory_usage()); + format_to!(buf, "\ncounts:\n{}", profile::countme::get_all()); if let Some(file_id) = file_id { format_to!(buf, "\nfile info:\n"); @@ -60,6 +61,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { None => format_to!(buf, "does not belong to any crate"), } } + buf } diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index f7231c2b8..cc7da27f7 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml @@ -14,6 +14,7 @@ once_cell = "1.3.1" cfg-if = "1" libc = "0.2.73" la-arena = { version = "0.2.0", path = "../../lib/arena" } +countme = { version = "2.0.0-pre.2", features = ["enable"] } jemalloc-ctl = { version = "0.3.3", optional = true } [target.'cfg(target_os = "linux")'.dependencies] diff --git a/crates/profile/src/hprof.rs b/crates/profile/src/hprof.rs index 8957ea016..29d2ed518 100644 --- a/crates/profile/src/hprof.rs +++ b/crates/profile/src/hprof.rs @@ -3,6 +3,7 @@ use once_cell::sync::Lazy; use std::{ cell::RefCell, collections::{BTreeMap, HashSet}, + env, io::{stderr, Write}, sync::{ atomic::{AtomicBool, Ordering}, @@ -18,7 +19,8 @@ use crate::tree::{Idx, Tree}; /// env RA_PROFILE=foo|bar|baz // enabled only selected entries /// env RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 ms pub fn init() { - let spec = std::env::var("RA_PROFILE").unwrap_or_default(); + countme::enable(env::var("RA_COUNT").is_ok()); + let spec = env::var("RA_PROFILE").unwrap_or_default(); init_from(&spec); } diff --git a/crates/profile/src/lib.rs b/crates/profile/src/lib.rs index aa6ccc36c..79dba47d5 100644 --- a/crates/profile/src/lib.rs +++ b/crates/profile/src/lib.rs @@ -15,6 +15,13 @@ pub use crate::{ stop_watch::{StopWatch, StopWatchSpan}, }; +pub use countme; +/// Include `_c: Count` field in important structs to count them. +/// +/// To view the counts, run with `RA_COUNT=1`. The overhead of disabled count is +/// almost zero. +pub use countme::Count; + thread_local!(static IN_SCOPE: RefCell = RefCell::new(false)); /// Allows to check if the current code is withing some dynamic scope, can be diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index fd1407e60..66416f709 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -2,6 +2,7 @@ //! errors. use std::{ + env, path::PathBuf, time::{SystemTime, UNIX_EPOCH}, }; @@ -295,6 +296,10 @@ impl AnalysisStatsCmd { report_metric("total memory", memory.allocated.megabytes() as u64, "MB"); } + if env::var("RA_COUNT").is_ok() { + eprintln!("{}", profile::countme::get_all()); + } + if self.memory_usage && verbosity.is_verbose() { print_memory_usage(host, vfs); } diff --git a/docs/dev/README.md b/docs/dev/README.md index dd2bfc493..24197b332 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -251,6 +251,9 @@ RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more tha In particular, I have `export RA_PROFILE='*>10'` in my shell profile. +We also have a "counting" profiler which counts number of instances of popular structs. +It is enabled by `RA_COUNT=1`. + To measure time for from-scratch analysis, use something like this: ``` -- cgit v1.2.3