Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 11c55b2

Browse files
committed
Auto merge of rust-lang#14629 - Veykril:stats, r=Veykril
internal: Add some additional status ouput We should be able to use this infra to get a better grasp about what we might want to LRU
2 parents 779b891 + 63e3bf1 commit 11c55b2

File tree

2 files changed

+175
-72
lines changed

2 files changed

+175
-72
lines changed

crates/ide/src/status.rs

Lines changed: 169 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1-
use std::{fmt, sync::Arc};
1+
use std::{fmt, marker::PhantomData, sync::Arc};
22

3-
use hir::{ExpandResult, MacroFile};
4-
use ide_db::base_db::{
5-
salsa::debug::{DebugQueryTable, TableEntry},
6-
CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId,
3+
use hir::{
4+
db::{AstIdMapQuery, AttrsQuery, ParseMacroExpansionQuery},
5+
Attr, Attrs, ExpandResult, MacroFile, Module,
6+
};
7+
use ide_db::{
8+
base_db::{
9+
salsa::{
10+
debug::{DebugQueryTable, TableEntry},
11+
Query, QueryTable,
12+
},
13+
CrateId, FileId, FileTextQuery, ParseQuery, SourceDatabase, SourceRootId,
14+
},
15+
symbol_index::ModuleSymbolsQuery,
716
};
817
use ide_db::{
918
symbol_index::{LibrarySymbolsQuery, SymbolIndex},
@@ -15,13 +24,6 @@ use std::env;
1524
use stdx::format_to;
1625
use syntax::{ast, Parse, SyntaxNode};
1726

18-
fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
19-
ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
20-
}
21-
fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
22-
hir::db::ParseMacroExpansionQuery.in_db(db).entries::<SyntaxTreeStats>()
23-
}
24-
2527
// Feature: Status
2628
//
2729
// Shows internal statistic about memory usage of rust-analyzer.
@@ -34,15 +36,21 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
3436
// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
3537
pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
3638
let mut buf = String::new();
37-
format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>());
38-
format_to!(buf, "{}\n", LibrarySymbolsQuery.in_db(db).entries::<LibrarySymbolsStats>());
39-
format_to!(buf, "{}\n", syntax_tree_stats(db));
40-
format_to!(buf, "{} (Macros)\n", macro_syntax_tree_stats(db));
39+
40+
format_to!(buf, "{}\n", collect_query(FileTextQuery.in_db(db)));
41+
format_to!(buf, "{}\n", collect_query(ParseQuery.in_db(db)));
42+
format_to!(buf, "{}\n", collect_query(ParseMacroExpansionQuery.in_db(db)));
43+
format_to!(buf, "{}\n", collect_query(LibrarySymbolsQuery.in_db(db)));
44+
format_to!(buf, "{}\n", collect_query(ModuleSymbolsQuery.in_db(db)));
4145
format_to!(buf, "{} in total\n", memory_usage());
4246
if env::var("RA_COUNT").is_ok() {
4347
format_to!(buf, "\nCounts:\n{}", profile::countme::get_all());
4448
}
4549

50+
format_to!(buf, "\nDebug info:\n");
51+
format_to!(buf, "{}\n", collect_query(AttrsQuery.in_db(db)));
52+
format_to!(buf, "{} ast id maps\n", collect_query_count(AstIdMapQuery.in_db(db)));
53+
4654
if let Some(file_id) = file_id {
4755
format_to!(buf, "\nFile info:\n");
4856
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 {
5260
let crate_graph = db.crate_graph();
5361
for krate in crates {
5462
let display_crate = |krate: CrateId| match &crate_graph[krate].display_name {
55-
Some(it) => format!("{it}({krate:?})"),
56-
None => format!("{krate:?}"),
63+
Some(it) => format!("{it}({})", krate.into_raw()),
64+
None => format!("{}", krate.into_raw()),
5765
};
5866
format_to!(buf, "Crate: {}\n", display_crate(krate));
5967
let deps = crate_graph[krate]
@@ -68,6 +76,82 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
6876
buf.trim().to_string()
6977
}
7078

79+
fn collect_query<'q, Q>(table: QueryTable<'q, Q>) -> <Q as QueryCollect>::Collector
80+
where
81+
QueryTable<'q, Q>: DebugQueryTable,
82+
Q: QueryCollect,
83+
<Q as Query>::Storage: 'q,
84+
<Q as QueryCollect>::Collector: StatCollect<
85+
<QueryTable<'q, Q> as DebugQueryTable>::Key,
86+
<QueryTable<'q, Q> as DebugQueryTable>::Value,
87+
>,
88+
{
89+
struct StatCollectorWrapper<C>(C);
90+
impl<C: StatCollect<K, V>, K, V> FromIterator<TableEntry<K, V>> for StatCollectorWrapper<C> {
91+
fn from_iter<T>(iter: T) -> StatCollectorWrapper<C>
92+
where
93+
T: IntoIterator<Item = TableEntry<K, V>>,
94+
{
95+
let mut res = C::default();
96+
for entry in iter {
97+
res.collect_entry(entry.key, entry.value);
98+
}
99+
StatCollectorWrapper(res)
100+
}
101+
}
102+
table.entries::<StatCollectorWrapper<<Q as QueryCollect>::Collector>>().0
103+
}
104+
105+
fn collect_query_count<'q, Q>(table: QueryTable<'q, Q>) -> usize
106+
where
107+
QueryTable<'q, Q>: DebugQueryTable,
108+
Q: Query,
109+
<Q as Query>::Storage: 'q,
110+
{
111+
struct EntryCounter(usize);
112+
impl<K, V> FromIterator<TableEntry<K, V>> for EntryCounter {
113+
fn from_iter<T>(iter: T) -> EntryCounter
114+
where
115+
T: IntoIterator<Item = TableEntry<K, V>>,
116+
{
117+
EntryCounter(iter.into_iter().count())
118+
}
119+
}
120+
table.entries::<EntryCounter>().0
121+
}
122+
123+
trait QueryCollect: Query {
124+
type Collector;
125+
}
126+
127+
impl QueryCollect for LibrarySymbolsQuery {
128+
type Collector = SymbolsStats<SourceRootId>;
129+
}
130+
131+
impl QueryCollect for ParseQuery {
132+
type Collector = SyntaxTreeStats<false>;
133+
}
134+
135+
impl QueryCollect for ParseMacroExpansionQuery {
136+
type Collector = SyntaxTreeStats<true>;
137+
}
138+
139+
impl QueryCollect for FileTextQuery {
140+
type Collector = FilesStats;
141+
}
142+
143+
impl QueryCollect for ModuleSymbolsQuery {
144+
type Collector = SymbolsStats<Module>;
145+
}
146+
147+
impl QueryCollect for AttrsQuery {
148+
type Collector = AttrsStats;
149+
}
150+
151+
trait StatCollect<K, V>: Default {
152+
fn collect_entry(&mut self, key: K, value: Option<V>);
153+
}
154+
71155
#[derive(Default)]
72156
struct FilesStats {
73157
total: usize,
@@ -80,85 +164,98 @@ impl fmt::Display for FilesStats {
80164
}
81165
}
82166

83-
impl FromIterator<TableEntry<FileId, Arc<String>>> for FilesStats {
84-
fn from_iter<T>(iter: T) -> FilesStats
85-
where
86-
T: IntoIterator<Item = TableEntry<FileId, Arc<String>>>,
87-
{
88-
let mut res = FilesStats::default();
89-
for entry in iter {
90-
res.total += 1;
91-
res.size += entry.value.unwrap().len();
92-
}
93-
res
167+
impl StatCollect<FileId, Arc<String>> for FilesStats {
168+
fn collect_entry(&mut self, _: FileId, value: Option<Arc<String>>) {
169+
self.total += 1;
170+
self.size += value.unwrap().len();
94171
}
95172
}
96173

97174
#[derive(Default)]
98-
pub(crate) struct SyntaxTreeStats {
175+
pub(crate) struct SyntaxTreeStats<const MACROS: bool> {
99176
total: usize,
100177
pub(crate) retained: usize,
101178
}
102179

103-
impl fmt::Display for SyntaxTreeStats {
180+
impl<const MACROS: bool> fmt::Display for SyntaxTreeStats<MACROS> {
104181
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
105-
write!(fmt, "{} trees, {} preserved", self.total, self.retained)
182+
write!(
183+
fmt,
184+
"{} trees, {} preserved{}",
185+
self.total,
186+
self.retained,
187+
if MACROS { " (macros)" } else { "" }
188+
)
106189
}
107190
}
108191

109-
impl FromIterator<TableEntry<FileId, Parse<ast::SourceFile>>> for SyntaxTreeStats {
110-
fn from_iter<T>(iter: T) -> SyntaxTreeStats
111-
where
112-
T: IntoIterator<Item = TableEntry<FileId, Parse<ast::SourceFile>>>,
113-
{
114-
let mut res = SyntaxTreeStats::default();
115-
for entry in iter {
116-
res.total += 1;
117-
res.retained += entry.value.is_some() as usize;
118-
}
119-
res
192+
impl StatCollect<FileId, Parse<ast::SourceFile>> for SyntaxTreeStats<false> {
193+
fn collect_entry(&mut self, _: FileId, value: Option<Parse<ast::SourceFile>>) {
194+
self.total += 1;
195+
self.retained += value.is_some() as usize;
120196
}
121197
}
122198

123-
impl<M> FromIterator<TableEntry<MacroFile, ExpandResult<(Parse<SyntaxNode>, M)>>>
124-
for SyntaxTreeStats
125-
{
126-
fn from_iter<T>(iter: T) -> SyntaxTreeStats
127-
where
128-
T: IntoIterator<Item = TableEntry<MacroFile, ExpandResult<(Parse<SyntaxNode>, M)>>>,
129-
{
130-
let mut res = SyntaxTreeStats::default();
131-
for entry in iter {
132-
res.total += 1;
133-
res.retained += entry.value.is_some() as usize;
134-
}
135-
res
199+
impl<M> StatCollect<MacroFile, ExpandResult<(Parse<SyntaxNode>, M)>> for SyntaxTreeStats<true> {
200+
fn collect_entry(&mut self, _: MacroFile, value: Option<ExpandResult<(Parse<SyntaxNode>, M)>>) {
201+
self.total += 1;
202+
self.retained += value.is_some() as usize;
136203
}
137204
}
138205

139-
#[derive(Default)]
140-
struct LibrarySymbolsStats {
206+
struct SymbolsStats<Key> {
141207
total: usize,
142208
size: Bytes,
209+
phantom: PhantomData<Key>,
143210
}
144211

145-
impl fmt::Display for LibrarySymbolsStats {
212+
impl<Key> Default for SymbolsStats<Key> {
213+
fn default() -> Self {
214+
Self { total: Default::default(), size: Default::default(), phantom: PhantomData }
215+
}
216+
}
217+
218+
impl fmt::Display for SymbolsStats<Module> {
146219
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
147-
write!(fmt, "{} of index symbols ({})", self.size, self.total)
220+
write!(fmt, "{} of module index symbols ({})", self.size, self.total)
221+
}
222+
}
223+
impl fmt::Display for SymbolsStats<SourceRootId> {
224+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
225+
write!(fmt, "{} of library index symbols ({})", self.size, self.total)
226+
}
227+
}
228+
impl<Key> StatCollect<Key, Arc<SymbolIndex>> for SymbolsStats<Key> {
229+
fn collect_entry(&mut self, _: Key, value: Option<Arc<SymbolIndex>>) {
230+
let symbols = value.unwrap();
231+
self.total += symbols.len();
232+
self.size += symbols.memory_size();
148233
}
149234
}
150235

151-
impl FromIterator<TableEntry<SourceRootId, Arc<SymbolIndex>>> for LibrarySymbolsStats {
152-
fn from_iter<T>(iter: T) -> LibrarySymbolsStats
153-
where
154-
T: IntoIterator<Item = TableEntry<SourceRootId, Arc<SymbolIndex>>>,
155-
{
156-
let mut res = LibrarySymbolsStats::default();
157-
for entry in iter {
158-
let symbols = entry.value.unwrap();
159-
res.total += symbols.len();
160-
res.size += symbols.memory_size();
161-
}
162-
res
236+
#[derive(Default)]
237+
struct AttrsStats {
238+
entries: usize,
239+
total: usize,
240+
}
241+
242+
impl fmt::Display for AttrsStats {
243+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
244+
let size =
245+
self.entries * std::mem::size_of::<Attrs>() + self.total * std::mem::size_of::<Attr>();
246+
let size = Bytes::new(size as _);
247+
write!(
248+
fmt,
249+
"{} attribute query entries, {} total attributes ({} for storing entries)",
250+
self.entries, self.total, size
251+
)
252+
}
253+
}
254+
255+
impl<Key> StatCollect<Key, Attrs> for AttrsStats {
256+
fn collect_entry(&mut self, _: Key, value: Option<Attrs>) {
257+
let attrs = value.unwrap();
258+
self.entries += 1;
259+
self.total += attrs.len();
163260
}
164261
}

crates/profile/src/memory_usage.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ fn memusage_linux() -> MemoryUsage {
9090
#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
9191
pub struct Bytes(isize);
9292

93+
impl Bytes {
94+
pub fn new(bytes: isize) -> Bytes {
95+
Bytes(bytes)
96+
}
97+
}
98+
9399
impl Bytes {
94100
pub fn megabytes(self) -> isize {
95101
self.0 / 1024 / 1024

0 commit comments

Comments
 (0)