Skip to content

Commit 51e8b8f

Browse files
committed
Add metrics for unevaluated constants, failed mir bodies, and failed data layouts
1 parent cbd14e9 commit 51e8b8f

File tree

2 files changed

+85
-18
lines changed

2 files changed

+85
-18
lines changed

crates/rust-analyzer/src/cli/analysis_stats.rs

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
//! errors.
33
44
use std::{
5-
collections::HashMap,
65
env,
76
time::{SystemTime, UNIX_EPOCH},
87
};
@@ -16,7 +15,7 @@ use hir_def::{
1615
hir::{ExprId, PatId},
1716
FunctionId,
1817
};
19-
use hir_ty::{Interner, TyExt, TypeFlags};
18+
use hir_ty::{Interner, Substitution, TyExt, TypeFlags};
2019
use ide::{Analysis, AnalysisHost, LineCol, RootDatabase};
2120
use ide_db::base_db::{
2221
salsa::{self, debug::DebugQueryTable, ParallelDatabase},
@@ -122,14 +121,19 @@ impl flags::AnalysisStats {
122121
eprint!(" crates: {num_crates}");
123122
let mut num_decls = 0;
124123
let mut funcs = Vec::new();
124+
let mut adts = Vec::new();
125+
let mut consts = Vec::new();
125126
while let Some(module) = visit_queue.pop() {
126127
if visited_modules.insert(module) {
127128
visit_queue.extend(module.children(db));
128129

129130
for decl in module.declarations(db) {
130131
num_decls += 1;
131-
if let ModuleDef::Function(f) = decl {
132-
funcs.push(f);
132+
match decl {
133+
ModuleDef::Function(f) => funcs.push(f),
134+
ModuleDef::Adt(a) => adts.push(a),
135+
ModuleDef::Const(c) => consts.push(c),
136+
_ => (),
133137
}
134138
}
135139

@@ -154,10 +158,13 @@ impl flags::AnalysisStats {
154158
self.run_inference(&host, db, &vfs, &funcs, verbosity);
155159
}
156160

157-
if self.mir_stats {
158-
self.lower_mir(db, &funcs);
161+
if !self.skip_mir_stats {
162+
self.run_mir_lowering(db, &funcs, verbosity);
159163
}
160164

165+
self.run_data_layout(db, &adts, verbosity);
166+
self.run_const_eval(db, &consts, verbosity);
167+
161168
let total_span = analysis_sw.elapsed();
162169
eprintln!("{:<20} {total_span}", "Total:");
163170
report_metric("total time", total_span.time.as_millis() as u64, "ms");
@@ -193,22 +200,82 @@ impl flags::AnalysisStats {
193200
Ok(())
194201
}
195202

196-
fn lower_mir(&self, db: &RootDatabase, funcs: &[Function]) {
197-
let all = funcs.len();
203+
fn run_data_layout(&self, db: &RootDatabase, adts: &[hir::Adt], verbosity: Verbosity) {
204+
let mut all = 0;
205+
let mut fail = 0;
206+
for &a in adts {
207+
if db.generic_params(a.into()).iter().next().is_some() {
208+
// Data types with generics don't have layout.
209+
continue;
210+
}
211+
all += 1;
212+
let Err(e) = db.layout_of_adt(hir_def::AdtId::from(a).into(), Substitution::empty(Interner)) else {
213+
continue;
214+
};
215+
if verbosity.is_spammy() {
216+
let full_name = a
217+
.module(db)
218+
.path_to_root(db)
219+
.into_iter()
220+
.rev()
221+
.filter_map(|it| it.name(db))
222+
.chain(Some(a.name(db)))
223+
.join("::");
224+
println!("Data layout for {full_name} failed due {e:?}");
225+
}
226+
fail += 1;
227+
}
228+
eprintln!("Failed data layouts: {fail} ({}%)", fail * 100 / all);
229+
report_metric("failed data layouts", fail, "#");
230+
}
231+
232+
fn run_const_eval(&self, db: &RootDatabase, consts: &[hir::Const], verbosity: Verbosity) {
233+
let mut all = 0;
234+
let mut fail = 0;
235+
for &c in consts {
236+
all += 1;
237+
let Err(e) = c.render_eval(db) else {
238+
continue;
239+
};
240+
if verbosity.is_spammy() {
241+
let full_name = c
242+
.module(db)
243+
.path_to_root(db)
244+
.into_iter()
245+
.rev()
246+
.filter_map(|it| it.name(db))
247+
.chain(c.name(db))
248+
.join("::");
249+
println!("Const eval for {full_name} failed due {e:?}");
250+
}
251+
fail += 1;
252+
}
253+
eprintln!("Failed const evals: {fail} ({}%)", fail * 100 / all);
254+
report_metric("failed const evals", fail, "#");
255+
}
256+
257+
fn run_mir_lowering(&self, db: &RootDatabase, funcs: &[Function], verbosity: Verbosity) {
258+
let all = funcs.len() as u64;
198259
let mut fail = 0;
199-
let mut h: HashMap<String, usize> = HashMap::new();
200260
for f in funcs {
201-
let f = FunctionId::from(*f);
202-
let Err(e) = db.mir_body(f.into()) else {
261+
let Err(e) = db.mir_body(FunctionId::from(*f).into()) else {
203262
continue;
204263
};
205-
let es = format!("{:?}", e);
206-
*h.entry(es).or_default() += 1;
264+
if verbosity.is_spammy() {
265+
let full_name = f
266+
.module(db)
267+
.path_to_root(db)
268+
.into_iter()
269+
.rev()
270+
.filter_map(|it| it.name(db))
271+
.chain(Some(f.name(db)))
272+
.join("::");
273+
println!("Mir body for {full_name} failed due {e:?}");
274+
}
207275
fail += 1;
208276
}
209-
let h = h.into_iter().sorted_by_key(|x| x.1).collect::<Vec<_>>();
210-
eprintln!("Mir failed reasons: {:#?}", h);
211277
eprintln!("Mir failed bodies: {fail} ({}%)", fail * 100 / all);
278+
report_metric("mir failed bodies", fail, "#");
212279
}
213280

214281
fn run_inference(

crates/rust-analyzer/src/cli/flags.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ xflags::xflags! {
6666
optional --memory-usage
6767
/// Print the total length of all source and macro files (whitespace is not counted).
6868
optional --source-stats
69-
/// Print the number of bodies that fail to lower to mir, in addition to failed reasons.
70-
optional --mir-stats
69+
/// Only type check, skip lowering to mir
70+
optional --skip-mir-stats
7171

7272
/// Only analyze items matching this path.
7373
optional -o, --only path: String
@@ -171,7 +171,7 @@ pub struct AnalysisStats {
171171
pub parallel: bool,
172172
pub memory_usage: bool,
173173
pub source_stats: bool,
174-
pub mir_stats: bool,
174+
pub skip_mir_stats: bool,
175175
pub only: Option<String>,
176176
pub with_deps: bool,
177177
pub no_sysroot: bool,

0 commit comments

Comments
 (0)