diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index 71fc91cf31..116e6b9751 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs @@ -1,9 +1,18 @@ -use std::{fmt, sync::Arc}; +use std::{fmt, marker::PhantomData, sync::Arc}; -use hir::{ExpandResult, MacroFile}; -use ide_db::base_db::{ - salsa::debug::{DebugQueryTable, TableEntry}, - CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId, +use hir::{ + db::{AstIdMapQuery, AttrsQuery, ParseMacroExpansionQuery}, + Attr, Attrs, ExpandResult, MacroFile, Module, +}; +use ide_db::{ + base_db::{ + salsa::{ + debug::{DebugQueryTable, TableEntry}, + Query, QueryTable, + }, + CrateId, FileId, FileTextQuery, ParseQuery, SourceDatabase, SourceRootId, + }, + symbol_index::ModuleSymbolsQuery, }; use ide_db::{ symbol_index::{LibrarySymbolsQuery, SymbolIndex}, @@ -15,13 +24,6 @@ use std::env; use stdx::format_to; use syntax::{ast, Parse, SyntaxNode}; -fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { - ide_db::base_db::ParseQuery.in_db(db).entries::() -} -fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { - hir::db::ParseMacroExpansionQuery.in_db(db).entries::() -} - // Feature: Status // // Shows internal statistic about memory usage of rust-analyzer. @@ -34,15 +36,21 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { // image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[] pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { let mut buf = String::new(); - format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::()); - format_to!(buf, "{}\n", LibrarySymbolsQuery.in_db(db).entries::()); - format_to!(buf, "{}\n", syntax_tree_stats(db)); - format_to!(buf, "{} (Macros)\n", macro_syntax_tree_stats(db)); + + format_to!(buf, "{}\n", collect_query(FileTextQuery.in_db(db))); + format_to!(buf, "{}\n", collect_query(ParseQuery.in_db(db))); + format_to!(buf, "{}\n", collect_query(ParseMacroExpansionQuery.in_db(db))); + format_to!(buf, "{}\n", collect_query(LibrarySymbolsQuery.in_db(db))); + format_to!(buf, "{}\n", collect_query(ModuleSymbolsQuery.in_db(db))); format_to!(buf, "{} in total\n", memory_usage()); if env::var("RA_COUNT").is_ok() { format_to!(buf, "\nCounts:\n{}", profile::countme::get_all()); } + format_to!(buf, "\nDebug info:\n"); + format_to!(buf, "{}\n", collect_query(AttrsQuery.in_db(db))); + format_to!(buf, "{} ast id maps\n", collect_query_count(AstIdMapQuery.in_db(db))); + if let Some(file_id) = file_id { format_to!(buf, "\nFile info:\n"); let crates = crate::parent_module::crates_for(db, file_id); @@ -52,8 +60,8 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { let crate_graph = db.crate_graph(); for krate in crates { let display_crate = |krate: CrateId| match &crate_graph[krate].display_name { - Some(it) => format!("{it}({krate:?})"), - None => format!("{krate:?}"), + Some(it) => format!("{it}({})", krate.into_raw()), + None => format!("{}", krate.into_raw()), }; format_to!(buf, "Crate: {}\n", display_crate(krate)); let deps = crate_graph[krate] @@ -68,6 +76,82 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { buf.trim().to_string() } +fn collect_query<'q, Q>(table: QueryTable<'q, Q>) -> ::Collector +where + QueryTable<'q, Q>: DebugQueryTable, + Q: QueryCollect, + ::Storage: 'q, + ::Collector: StatCollect< + as DebugQueryTable>::Key, + as DebugQueryTable>::Value, + >, +{ + struct StatCollectorWrapper(C); + impl, K, V> FromIterator> for StatCollectorWrapper { + fn from_iter(iter: T) -> StatCollectorWrapper + where + T: IntoIterator>, + { + let mut res = C::default(); + for entry in iter { + res.collect_entry(entry.key, entry.value); + } + StatCollectorWrapper(res) + } + } + table.entries::::Collector>>().0 +} + +fn collect_query_count<'q, Q>(table: QueryTable<'q, Q>) -> usize +where + QueryTable<'q, Q>: DebugQueryTable, + Q: Query, + ::Storage: 'q, +{ + struct EntryCounter(usize); + impl FromIterator> for EntryCounter { + fn from_iter(iter: T) -> EntryCounter + where + T: IntoIterator>, + { + EntryCounter(iter.into_iter().count()) + } + } + table.entries::().0 +} + +trait QueryCollect: Query { + type Collector; +} + +impl QueryCollect for LibrarySymbolsQuery { + type Collector = SymbolsStats; +} + +impl QueryCollect for ParseQuery { + type Collector = SyntaxTreeStats; +} + +impl QueryCollect for ParseMacroExpansionQuery { + type Collector = SyntaxTreeStats; +} + +impl QueryCollect for FileTextQuery { + type Collector = FilesStats; +} + +impl QueryCollect for ModuleSymbolsQuery { + type Collector = SymbolsStats; +} + +impl QueryCollect for AttrsQuery { + type Collector = AttrsStats; +} + +trait StatCollect: Default { + fn collect_entry(&mut self, key: K, value: Option); +} + #[derive(Default)] struct FilesStats { total: usize, @@ -80,85 +164,98 @@ impl fmt::Display for FilesStats { } } -impl FromIterator>> for FilesStats { - fn from_iter(iter: T) -> FilesStats - where - T: IntoIterator>>, - { - let mut res = FilesStats::default(); - for entry in iter { - res.total += 1; - res.size += entry.value.unwrap().len(); - } - res +impl StatCollect> for FilesStats { + fn collect_entry(&mut self, _: FileId, value: Option>) { + self.total += 1; + self.size += value.unwrap().len(); } } #[derive(Default)] -pub(crate) struct SyntaxTreeStats { +pub(crate) struct SyntaxTreeStats { total: usize, pub(crate) retained: usize, } -impl fmt::Display for SyntaxTreeStats { +impl fmt::Display for SyntaxTreeStats { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{} trees, {} preserved", self.total, self.retained) + write!( + fmt, + "{} trees, {} preserved{}", + self.total, + self.retained, + if MACROS { " (macros)" } else { "" } + ) } } -impl FromIterator>> for SyntaxTreeStats { - fn from_iter(iter: T) -> SyntaxTreeStats - where - T: IntoIterator>>, - { - let mut res = SyntaxTreeStats::default(); - for entry in iter { - res.total += 1; - res.retained += entry.value.is_some() as usize; - } - res +impl StatCollect> for SyntaxTreeStats { + fn collect_entry(&mut self, _: FileId, value: Option>) { + self.total += 1; + self.retained += value.is_some() as usize; } } -impl FromIterator, M)>>> - for SyntaxTreeStats -{ - fn from_iter(iter: T) -> SyntaxTreeStats - where - T: IntoIterator, M)>>>, - { - let mut res = SyntaxTreeStats::default(); - for entry in iter { - res.total += 1; - res.retained += entry.value.is_some() as usize; - } - res +impl StatCollect, M)>> for SyntaxTreeStats { + fn collect_entry(&mut self, _: MacroFile, value: Option, M)>>) { + self.total += 1; + self.retained += value.is_some() as usize; + } +} + +struct SymbolsStats { + total: usize, + size: Bytes, + phantom: PhantomData, +} + +impl Default for SymbolsStats { + fn default() -> Self { + Self { total: Default::default(), size: Default::default(), phantom: PhantomData } + } +} + +impl fmt::Display for SymbolsStats { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{} of module index symbols ({})", self.size, self.total) + } +} +impl fmt::Display for SymbolsStats { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{} of library index symbols ({})", self.size, self.total) + } +} +impl StatCollect> for SymbolsStats { + fn collect_entry(&mut self, _: Key, value: Option>) { + let symbols = value.unwrap(); + self.total += symbols.len(); + self.size += symbols.memory_size(); } } #[derive(Default)] -struct LibrarySymbolsStats { +struct AttrsStats { + entries: usize, total: usize, - size: Bytes, } -impl fmt::Display for LibrarySymbolsStats { +impl fmt::Display for AttrsStats { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{} of index symbols ({})", self.size, self.total) + let size = + self.entries * std::mem::size_of::() + self.total * std::mem::size_of::(); + let size = Bytes::new(size as _); + write!( + fmt, + "{} attribute query entries, {} total attributes ({} for storing entries)", + self.entries, self.total, size + ) } } -impl FromIterator>> for LibrarySymbolsStats { - fn from_iter(iter: T) -> LibrarySymbolsStats - where - T: IntoIterator>>, - { - let mut res = LibrarySymbolsStats::default(); - for entry in iter { - let symbols = entry.value.unwrap(); - res.total += symbols.len(); - res.size += symbols.memory_size(); - } - res +impl StatCollect for AttrsStats { + fn collect_entry(&mut self, _: Key, value: Option) { + let attrs = value.unwrap(); + self.entries += 1; + self.total += attrs.len(); } } diff --git a/crates/profile/src/memory_usage.rs b/crates/profile/src/memory_usage.rs index 8017f86579..f089c78e0c 100644 --- a/crates/profile/src/memory_usage.rs +++ b/crates/profile/src/memory_usage.rs @@ -90,6 +90,12 @@ fn memusage_linux() -> MemoryUsage { #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] pub struct Bytes(isize); +impl Bytes { + pub fn new(bytes: isize) -> Bytes { + Bytes(bytes) + } +} + impl Bytes { pub fn megabytes(self) -> isize { self.0 / 1024 / 1024