mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
internal: Add some additional status ouput
This commit is contained in:
parent
e7285507f6
commit
63e3bf118d
2 changed files with 175 additions and 72 deletions
|
@ -1,9 +1,18 @@
|
||||||
use std::{fmt, sync::Arc};
|
use std::{fmt, marker::PhantomData, sync::Arc};
|
||||||
|
|
||||||
use hir::{ExpandResult, MacroFile};
|
use hir::{
|
||||||
use ide_db::base_db::{
|
db::{AstIdMapQuery, AttrsQuery, ParseMacroExpansionQuery},
|
||||||
salsa::debug::{DebugQueryTable, TableEntry},
|
Attr, Attrs, ExpandResult, MacroFile, Module,
|
||||||
CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId,
|
};
|
||||||
|
use ide_db::{
|
||||||
|
base_db::{
|
||||||
|
salsa::{
|
||||||
|
debug::{DebugQueryTable, TableEntry},
|
||||||
|
Query, QueryTable,
|
||||||
|
},
|
||||||
|
CrateId, FileId, FileTextQuery, ParseQuery, SourceDatabase, SourceRootId,
|
||||||
|
},
|
||||||
|
symbol_index::ModuleSymbolsQuery,
|
||||||
};
|
};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
symbol_index::{LibrarySymbolsQuery, SymbolIndex},
|
symbol_index::{LibrarySymbolsQuery, SymbolIndex},
|
||||||
|
@ -15,13 +24,6 @@ use std::env;
|
||||||
use stdx::format_to;
|
use stdx::format_to;
|
||||||
use syntax::{ast, Parse, SyntaxNode};
|
use syntax::{ast, Parse, SyntaxNode};
|
||||||
|
|
||||||
fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
|
|
||||||
ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
|
|
||||||
}
|
|
||||||
fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
|
|
||||||
hir::db::ParseMacroExpansionQuery.in_db(db).entries::<SyntaxTreeStats>()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Feature: Status
|
// Feature: Status
|
||||||
//
|
//
|
||||||
// Shows internal statistic about memory usage of rust-analyzer.
|
// 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[]
|
// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
|
||||||
pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
|
pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>());
|
|
||||||
format_to!(buf, "{}\n", LibrarySymbolsQuery.in_db(db).entries::<LibrarySymbolsStats>());
|
format_to!(buf, "{}\n", collect_query(FileTextQuery.in_db(db)));
|
||||||
format_to!(buf, "{}\n", syntax_tree_stats(db));
|
format_to!(buf, "{}\n", collect_query(ParseQuery.in_db(db)));
|
||||||
format_to!(buf, "{} (Macros)\n", macro_syntax_tree_stats(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());
|
format_to!(buf, "{} in total\n", memory_usage());
|
||||||
if env::var("RA_COUNT").is_ok() {
|
if env::var("RA_COUNT").is_ok() {
|
||||||
format_to!(buf, "\nCounts:\n{}", profile::countme::get_all());
|
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 {
|
if let Some(file_id) = file_id {
|
||||||
format_to!(buf, "\nFile info:\n");
|
format_to!(buf, "\nFile info:\n");
|
||||||
let crates = crate::parent_module::crates_for(db, file_id);
|
let crates = crate::parent_module::crates_for(db, file_id);
|
||||||
|
@ -52,8 +60,8 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
|
||||||
let crate_graph = db.crate_graph();
|
let crate_graph = db.crate_graph();
|
||||||
for krate in crates {
|
for krate in crates {
|
||||||
let display_crate = |krate: CrateId| match &crate_graph[krate].display_name {
|
let display_crate = |krate: CrateId| match &crate_graph[krate].display_name {
|
||||||
Some(it) => format!("{it}({krate:?})"),
|
Some(it) => format!("{it}({})", krate.into_raw()),
|
||||||
None => format!("{krate:?}"),
|
None => format!("{}", krate.into_raw()),
|
||||||
};
|
};
|
||||||
format_to!(buf, "Crate: {}\n", display_crate(krate));
|
format_to!(buf, "Crate: {}\n", display_crate(krate));
|
||||||
let deps = crate_graph[krate]
|
let deps = crate_graph[krate]
|
||||||
|
@ -68,6 +76,82 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
|
||||||
buf.trim().to_string()
|
buf.trim().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn collect_query<'q, Q>(table: QueryTable<'q, Q>) -> <Q as QueryCollect>::Collector
|
||||||
|
where
|
||||||
|
QueryTable<'q, Q>: DebugQueryTable,
|
||||||
|
Q: QueryCollect,
|
||||||
|
<Q as Query>::Storage: 'q,
|
||||||
|
<Q as QueryCollect>::Collector: StatCollect<
|
||||||
|
<QueryTable<'q, Q> as DebugQueryTable>::Key,
|
||||||
|
<QueryTable<'q, Q> as DebugQueryTable>::Value,
|
||||||
|
>,
|
||||||
|
{
|
||||||
|
struct StatCollectorWrapper<C>(C);
|
||||||
|
impl<C: StatCollect<K, V>, K, V> FromIterator<TableEntry<K, V>> for StatCollectorWrapper<C> {
|
||||||
|
fn from_iter<T>(iter: T) -> StatCollectorWrapper<C>
|
||||||
|
where
|
||||||
|
T: IntoIterator<Item = TableEntry<K, V>>,
|
||||||
|
{
|
||||||
|
let mut res = C::default();
|
||||||
|
for entry in iter {
|
||||||
|
res.collect_entry(entry.key, entry.value);
|
||||||
|
}
|
||||||
|
StatCollectorWrapper(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table.entries::<StatCollectorWrapper<<Q as QueryCollect>::Collector>>().0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_query_count<'q, Q>(table: QueryTable<'q, Q>) -> usize
|
||||||
|
where
|
||||||
|
QueryTable<'q, Q>: DebugQueryTable,
|
||||||
|
Q: Query,
|
||||||
|
<Q as Query>::Storage: 'q,
|
||||||
|
{
|
||||||
|
struct EntryCounter(usize);
|
||||||
|
impl<K, V> FromIterator<TableEntry<K, V>> for EntryCounter {
|
||||||
|
fn from_iter<T>(iter: T) -> EntryCounter
|
||||||
|
where
|
||||||
|
T: IntoIterator<Item = TableEntry<K, V>>,
|
||||||
|
{
|
||||||
|
EntryCounter(iter.into_iter().count())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table.entries::<EntryCounter>().0
|
||||||
|
}
|
||||||
|
|
||||||
|
trait QueryCollect: Query {
|
||||||
|
type Collector;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QueryCollect for LibrarySymbolsQuery {
|
||||||
|
type Collector = SymbolsStats<SourceRootId>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QueryCollect for ParseQuery {
|
||||||
|
type Collector = SyntaxTreeStats<false>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QueryCollect for ParseMacroExpansionQuery {
|
||||||
|
type Collector = SyntaxTreeStats<true>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QueryCollect for FileTextQuery {
|
||||||
|
type Collector = FilesStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QueryCollect for ModuleSymbolsQuery {
|
||||||
|
type Collector = SymbolsStats<Module>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QueryCollect for AttrsQuery {
|
||||||
|
type Collector = AttrsStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait StatCollect<K, V>: Default {
|
||||||
|
fn collect_entry(&mut self, key: K, value: Option<V>);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct FilesStats {
|
struct FilesStats {
|
||||||
total: usize,
|
total: usize,
|
||||||
|
@ -80,85 +164,98 @@ impl fmt::Display for FilesStats {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator<TableEntry<FileId, Arc<String>>> for FilesStats {
|
impl StatCollect<FileId, Arc<String>> for FilesStats {
|
||||||
fn from_iter<T>(iter: T) -> FilesStats
|
fn collect_entry(&mut self, _: FileId, value: Option<Arc<String>>) {
|
||||||
where
|
self.total += 1;
|
||||||
T: IntoIterator<Item = TableEntry<FileId, Arc<String>>>,
|
self.size += value.unwrap().len();
|
||||||
{
|
|
||||||
let mut res = FilesStats::default();
|
|
||||||
for entry in iter {
|
|
||||||
res.total += 1;
|
|
||||||
res.size += entry.value.unwrap().len();
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct SyntaxTreeStats {
|
pub(crate) struct SyntaxTreeStats<const MACROS: bool> {
|
||||||
total: usize,
|
total: usize,
|
||||||
pub(crate) retained: usize,
|
pub(crate) retained: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for SyntaxTreeStats {
|
impl<const MACROS: bool> fmt::Display for SyntaxTreeStats<MACROS> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
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<TableEntry<FileId, Parse<ast::SourceFile>>> for SyntaxTreeStats {
|
impl StatCollect<FileId, Parse<ast::SourceFile>> for SyntaxTreeStats<false> {
|
||||||
fn from_iter<T>(iter: T) -> SyntaxTreeStats
|
fn collect_entry(&mut self, _: FileId, value: Option<Parse<ast::SourceFile>>) {
|
||||||
where
|
self.total += 1;
|
||||||
T: IntoIterator<Item = TableEntry<FileId, Parse<ast::SourceFile>>>,
|
self.retained += value.is_some() as usize;
|
||||||
{
|
|
||||||
let mut res = SyntaxTreeStats::default();
|
|
||||||
for entry in iter {
|
|
||||||
res.total += 1;
|
|
||||||
res.retained += entry.value.is_some() as usize;
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> FromIterator<TableEntry<MacroFile, ExpandResult<(Parse<SyntaxNode>, M)>>>
|
impl<M> StatCollect<MacroFile, ExpandResult<(Parse<SyntaxNode>, M)>> for SyntaxTreeStats<true> {
|
||||||
for SyntaxTreeStats
|
fn collect_entry(&mut self, _: MacroFile, value: Option<ExpandResult<(Parse<SyntaxNode>, M)>>) {
|
||||||
{
|
self.total += 1;
|
||||||
fn from_iter<T>(iter: T) -> SyntaxTreeStats
|
self.retained += value.is_some() as usize;
|
||||||
where
|
}
|
||||||
T: IntoIterator<Item = TableEntry<MacroFile, ExpandResult<(Parse<SyntaxNode>, M)>>>,
|
}
|
||||||
{
|
|
||||||
let mut res = SyntaxTreeStats::default();
|
struct SymbolsStats<Key> {
|
||||||
for entry in iter {
|
total: usize,
|
||||||
res.total += 1;
|
size: Bytes,
|
||||||
res.retained += entry.value.is_some() as usize;
|
phantom: PhantomData<Key>,
|
||||||
}
|
}
|
||||||
res
|
|
||||||
|
impl<Key> Default for SymbolsStats<Key> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { total: Default::default(), size: Default::default(), phantom: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SymbolsStats<Module> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(fmt, "{} of module index symbols ({})", self.size, self.total)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl fmt::Display for SymbolsStats<SourceRootId> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(fmt, "{} of library index symbols ({})", self.size, self.total)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<Key> StatCollect<Key, Arc<SymbolIndex>> for SymbolsStats<Key> {
|
||||||
|
fn collect_entry(&mut self, _: Key, value: Option<Arc<SymbolIndex>>) {
|
||||||
|
let symbols = value.unwrap();
|
||||||
|
self.total += symbols.len();
|
||||||
|
self.size += symbols.memory_size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct LibrarySymbolsStats {
|
struct AttrsStats {
|
||||||
|
entries: usize,
|
||||||
total: usize,
|
total: usize,
|
||||||
size: Bytes,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for LibrarySymbolsStats {
|
impl fmt::Display for AttrsStats {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
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::<Attrs>() + self.total * std::mem::size_of::<Attr>();
|
||||||
|
let size = Bytes::new(size as _);
|
||||||
|
write!(
|
||||||
|
fmt,
|
||||||
|
"{} attribute query entries, {} total attributes ({} for storing entries)",
|
||||||
|
self.entries, self.total, size
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator<TableEntry<SourceRootId, Arc<SymbolIndex>>> for LibrarySymbolsStats {
|
impl<Key> StatCollect<Key, Attrs> for AttrsStats {
|
||||||
fn from_iter<T>(iter: T) -> LibrarySymbolsStats
|
fn collect_entry(&mut self, _: Key, value: Option<Attrs>) {
|
||||||
where
|
let attrs = value.unwrap();
|
||||||
T: IntoIterator<Item = TableEntry<SourceRootId, Arc<SymbolIndex>>>,
|
self.entries += 1;
|
||||||
{
|
self.total += attrs.len();
|
||||||
let mut res = LibrarySymbolsStats::default();
|
|
||||||
for entry in iter {
|
|
||||||
let symbols = entry.value.unwrap();
|
|
||||||
res.total += symbols.len();
|
|
||||||
res.size += symbols.memory_size();
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,12 @@ fn memusage_linux() -> MemoryUsage {
|
||||||
#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||||
pub struct Bytes(isize);
|
pub struct Bytes(isize);
|
||||||
|
|
||||||
|
impl Bytes {
|
||||||
|
pub fn new(bytes: isize) -> Bytes {
|
||||||
|
Bytes(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Bytes {
|
impl Bytes {
|
||||||
pub fn megabytes(self) -> isize {
|
pub fn megabytes(self) -> isize {
|
||||||
self.0 / 1024 / 1024
|
self.0 / 1024 / 1024
|
||||||
|
|
Loading…
Reference in a new issue