diff options
Diffstat (limited to 'crates/ide/src/status.rs')
-rw-r--r-- | crates/ide/src/status.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs new file mode 100644 index 000000000..c23708181 --- /dev/null +++ b/crates/ide/src/status.rs | |||
@@ -0,0 +1,145 @@ | |||
1 | use std::{fmt, iter::FromIterator, sync::Arc}; | ||
2 | |||
3 | use base_db::{ | ||
4 | salsa::debug::{DebugQueryTable, TableEntry}, | ||
5 | FileTextQuery, SourceRootId, | ||
6 | }; | ||
7 | use hir::MacroFile; | ||
8 | use ide_db::{ | ||
9 | symbol_index::{LibrarySymbolsQuery, SymbolIndex}, | ||
10 | RootDatabase, | ||
11 | }; | ||
12 | use profile::{memory_usage, Bytes}; | ||
13 | use rustc_hash::FxHashMap; | ||
14 | use syntax::{ast, Parse, SyntaxNode}; | ||
15 | |||
16 | use crate::FileId; | ||
17 | |||
18 | fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { | ||
19 | base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>() | ||
20 | } | ||
21 | fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { | ||
22 | hir::db::ParseMacroQuery.in_db(db).entries::<SyntaxTreeStats>() | ||
23 | } | ||
24 | |||
25 | // Feature: Status | ||
26 | // | ||
27 | // Shows internal statistic about memory usage of rust-analyzer. | ||
28 | // | ||
29 | // |=== | ||
30 | // | Editor | Action Name | ||
31 | // | ||
32 | // | VS Code | **Rust Analyzer: Status** | ||
33 | // |=== | ||
34 | pub(crate) fn status(db: &RootDatabase) -> String { | ||
35 | let files_stats = FileTextQuery.in_db(db).entries::<FilesStats>(); | ||
36 | let syntax_tree_stats = syntax_tree_stats(db); | ||
37 | let macro_syntax_tree_stats = macro_syntax_tree_stats(db); | ||
38 | let symbols_stats = LibrarySymbolsQuery.in_db(db).entries::<LibrarySymbolsStats>(); | ||
39 | format!( | ||
40 | "{}\n{}\n{}\n{} (macros)\n\n\nmemory:\n{}\ngc {:?} seconds ago", | ||
41 | files_stats, | ||
42 | symbols_stats, | ||
43 | syntax_tree_stats, | ||
44 | macro_syntax_tree_stats, | ||
45 | memory_usage(), | ||
46 | db.last_gc.elapsed().as_secs(), | ||
47 | ) | ||
48 | } | ||
49 | |||
50 | #[derive(Default)] | ||
51 | struct FilesStats { | ||
52 | total: usize, | ||
53 | size: Bytes, | ||
54 | } | ||
55 | |||
56 | impl fmt::Display for FilesStats { | ||
57 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
58 | write!(fmt, "{} ({}) files", self.total, self.size) | ||
59 | } | ||
60 | } | ||
61 | |||
62 | impl FromIterator<TableEntry<FileId, Arc<String>>> for FilesStats { | ||
63 | fn from_iter<T>(iter: T) -> FilesStats | ||
64 | where | ||
65 | T: IntoIterator<Item = TableEntry<FileId, Arc<String>>>, | ||
66 | { | ||
67 | let mut res = FilesStats::default(); | ||
68 | for entry in iter { | ||
69 | res.total += 1; | ||
70 | res.size += entry.value.unwrap().len(); | ||
71 | } | ||
72 | res | ||
73 | } | ||
74 | } | ||
75 | |||
76 | #[derive(Default)] | ||
77 | pub(crate) struct SyntaxTreeStats { | ||
78 | total: usize, | ||
79 | pub(crate) retained: usize, | ||
80 | } | ||
81 | |||
82 | impl fmt::Display for SyntaxTreeStats { | ||
83 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
84 | write!(fmt, "{} trees, {} retained", self.total, self.retained) | ||
85 | } | ||
86 | } | ||
87 | |||
88 | impl FromIterator<TableEntry<FileId, Parse<ast::SourceFile>>> for SyntaxTreeStats { | ||
89 | fn from_iter<T>(iter: T) -> SyntaxTreeStats | ||
90 | where | ||
91 | T: IntoIterator<Item = TableEntry<FileId, Parse<ast::SourceFile>>>, | ||
92 | { | ||
93 | let mut res = SyntaxTreeStats::default(); | ||
94 | for entry in iter { | ||
95 | res.total += 1; | ||
96 | res.retained += entry.value.is_some() as usize; | ||
97 | } | ||
98 | res | ||
99 | } | ||
100 | } | ||
101 | |||
102 | impl<M> FromIterator<TableEntry<MacroFile, Option<(Parse<SyntaxNode>, M)>>> for SyntaxTreeStats { | ||
103 | fn from_iter<T>(iter: T) -> SyntaxTreeStats | ||
104 | where | ||
105 | T: IntoIterator<Item = TableEntry<MacroFile, Option<(Parse<SyntaxNode>, M)>>>, | ||
106 | { | ||
107 | let mut res = SyntaxTreeStats::default(); | ||
108 | for entry in iter { | ||
109 | res.total += 1; | ||
110 | res.retained += entry.value.is_some() as usize; | ||
111 | } | ||
112 | res | ||
113 | } | ||
114 | } | ||
115 | |||
116 | #[derive(Default)] | ||
117 | struct LibrarySymbolsStats { | ||
118 | total: usize, | ||
119 | size: Bytes, | ||
120 | } | ||
121 | |||
122 | impl fmt::Display for LibrarySymbolsStats { | ||
123 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
124 | write!(fmt, "{} ({}) symbols", self.total, self.size) | ||
125 | } | ||
126 | } | ||
127 | |||
128 | impl FromIterator<TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>> | ||
129 | for LibrarySymbolsStats | ||
130 | { | ||
131 | fn from_iter<T>(iter: T) -> LibrarySymbolsStats | ||
132 | where | ||
133 | T: IntoIterator<Item = TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>, | ||
134 | { | ||
135 | let mut res = LibrarySymbolsStats::default(); | ||
136 | for entry in iter { | ||
137 | let value = entry.value.unwrap(); | ||
138 | for symbols in value.values() { | ||
139 | res.total += symbols.len(); | ||
140 | res.size += symbols.memory_size(); | ||
141 | } | ||
142 | } | ||
143 | res | ||
144 | } | ||
145 | } | ||