use std::{fmt, iter::FromIterator, sync::Arc}; use base_db::{ salsa::debug::{DebugQueryTable, TableEntry}, FileTextQuery, SourceRootId, }; use hir::MacroFile; use ide_db::{ symbol_index::{LibrarySymbolsQuery, SymbolIndex}, RootDatabase, }; use profile::{memory_usage, Bytes}; use rustc_hash::FxHashMap; use syntax::{ast, Parse, SyntaxNode}; use crate::FileId; fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { base_db::ParseQuery.in_db(db).entries::() } fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { hir::db::ParseMacroQuery.in_db(db).entries::() } // Feature: Status // // Shows internal statistic about memory usage of rust-analyzer. // // |=== // | Editor | Action Name // // | VS Code | **Rust Analyzer: Status** // |=== pub(crate) fn status(db: &RootDatabase) -> String { let files_stats = FileTextQuery.in_db(db).entries::(); let syntax_tree_stats = syntax_tree_stats(db); let macro_syntax_tree_stats = macro_syntax_tree_stats(db); let symbols_stats = LibrarySymbolsQuery.in_db(db).entries::(); format!( "{}\n{}\n{}\n{} (macros)\n\n\nmemory:\n{}\ngc {:?} seconds ago", files_stats, symbols_stats, syntax_tree_stats, macro_syntax_tree_stats, memory_usage(), db.last_gc.elapsed().as_secs(), ) } #[derive(Default)] struct FilesStats { total: usize, size: Bytes, } impl fmt::Display for FilesStats { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "{} ({}) files", self.total, self.size) } } 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 } } #[derive(Default)] pub(crate) struct SyntaxTreeStats { total: usize, pub(crate) retained: usize, } impl fmt::Display for SyntaxTreeStats { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "{} trees, {} retained", self.total, self.retained) } } 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 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 } } #[derive(Default)] struct LibrarySymbolsStats { total: usize, size: Bytes, } impl fmt::Display for LibrarySymbolsStats { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "{} ({}) symbols", self.total, self.size) } } impl FromIterator>>> for LibrarySymbolsStats { fn from_iter(iter: T) -> LibrarySymbolsStats where T: IntoIterator>>>, { let mut res = LibrarySymbolsStats::default(); for entry in iter { let value = entry.value.unwrap(); for symbols in value.values() { res.total += symbols.len(); res.size += symbols.memory_size(); } } res } }