Skip to content

Commit

Permalink
Auto merge of rust-lang#14808 - HKalbasi:metrics, r=HKalbasi
Browse files Browse the repository at this point in the history
Add metrics for unevaluated constants, failed mir bodies, and failed data layouts

fix rust-lang#14803
  • Loading branch information
bors committed May 14, 2023
2 parents cbd14e9 + 206a0b5 commit e5c7228
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 19 deletions.
19 changes: 19 additions & 0 deletions crates/hir-ty/src/consteval/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2066,3 +2066,22 @@ fn type_error() {
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::TypeMismatch(_))),
);
}

#[test]
fn unsized_local() {
check_fail(
r#"
//- minicore: coerce_unsized, index, slice
const fn x() -> SomeUnknownTypeThatDereferenceToSlice {
SomeUnknownTypeThatDereferenceToSlice
}
const GOAL: u16 = {
let y = x();
let z: &[u16] = &y;
z[1]
};
"#,
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::UnsizedTemporary(_))),
);
}
4 changes: 3 additions & 1 deletion crates/hir-ty/src/mir/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ pub enum MirLowerError {
RecordLiteralWithoutPath,
UnresolvedMethod(String),
UnresolvedField,
UnsizedTemporary(Ty),
MissingFunctionDefinition,
TypeMismatch(TypeMismatch),
/// This should be never happen. Type mismatch should catch everything.
Expand Down Expand Up @@ -108,6 +109,7 @@ impl MirLowerError {
}
}
MirLowerError::LayoutError(_)
| MirLowerError::UnsizedTemporary(_)
| MirLowerError::IncompleteExpr
| MirLowerError::UnaccessableLocal
| MirLowerError::TraitFunctionDefinition(_, _)
Expand Down Expand Up @@ -199,7 +201,7 @@ impl<'ctx> MirLowerCtx<'ctx> {

fn temp(&mut self, ty: Ty) -> Result<LocalId> {
if matches!(ty.kind(Interner), TyKind::Slice(_) | TyKind::Dyn(_)) {
implementation_error!("unsized temporaries");
return Err(MirLowerError::UnsizedTemporary(ty));
}
Ok(self.result.locals.alloc(Local { ty }))
}
Expand Down
103 changes: 88 additions & 15 deletions crates/rust-analyzer/src/cli/analysis_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
//! errors.

use std::{
collections::HashMap,
env,
time::{SystemTime, UNIX_EPOCH},
};
Expand All @@ -16,7 +15,7 @@ use hir_def::{
hir::{ExprId, PatId},
FunctionId,
};
use hir_ty::{Interner, TyExt, TypeFlags};
use hir_ty::{Interner, Substitution, TyExt, TypeFlags};
use ide::{Analysis, AnalysisHost, LineCol, RootDatabase};
use ide_db::base_db::{
salsa::{self, debug::DebugQueryTable, ParallelDatabase},
Expand Down Expand Up @@ -122,14 +121,19 @@ impl flags::AnalysisStats {
eprint!(" crates: {num_crates}");
let mut num_decls = 0;
let mut funcs = Vec::new();
let mut adts = Vec::new();
let mut consts = Vec::new();
while let Some(module) = visit_queue.pop() {
if visited_modules.insert(module) {
visit_queue.extend(module.children(db));

for decl in module.declarations(db) {
num_decls += 1;
if let ModuleDef::Function(f) = decl {
funcs.push(f);
match decl {
ModuleDef::Function(f) => funcs.push(f),
ModuleDef::Adt(a) => adts.push(a),
ModuleDef::Const(c) => consts.push(c),
_ => (),
}
}

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

if self.mir_stats {
self.lower_mir(db, &funcs);
if !self.skip_mir_stats {
self.run_mir_lowering(db, &funcs, verbosity);
}

self.run_data_layout(db, &adts, verbosity);
self.run_const_eval(db, &consts, verbosity);

let total_span = analysis_sw.elapsed();
eprintln!("{:<20} {total_span}", "Total:");
report_metric("total time", total_span.time.as_millis() as u64, "ms");
Expand Down Expand Up @@ -193,22 +200,88 @@ impl flags::AnalysisStats {
Ok(())
}

fn lower_mir(&self, db: &RootDatabase, funcs: &[Function]) {
let all = funcs.len();
fn run_data_layout(&self, db: &RootDatabase, adts: &[hir::Adt], verbosity: Verbosity) {
let mut sw = self.stop_watch();
let mut all = 0;
let mut fail = 0;
for &a in adts {
if db.generic_params(a.into()).iter().next().is_some() {
// Data types with generics don't have layout.
continue;
}
all += 1;
let Err(e) = db.layout_of_adt(hir_def::AdtId::from(a).into(), Substitution::empty(Interner)) else {
continue;
};
if verbosity.is_spammy() {
let full_name = a
.module(db)
.path_to_root(db)
.into_iter()
.rev()
.filter_map(|it| it.name(db))
.chain(Some(a.name(db)))
.join("::");
println!("Data layout for {full_name} failed due {e:?}");
}
fail += 1;
}
eprintln!("{:<20} {}", "Data layouts:", sw.elapsed());
eprintln!("Failed data layouts: {fail} ({}%)", fail * 100 / all);
report_metric("failed data layouts", fail, "#");
}

fn run_const_eval(&self, db: &RootDatabase, consts: &[hir::Const], verbosity: Verbosity) {
let mut sw = self.stop_watch();
let mut all = 0;
let mut fail = 0;
for &c in consts {
all += 1;
let Err(e) = c.render_eval(db) else {
continue;
};
if verbosity.is_spammy() {
let full_name = c
.module(db)
.path_to_root(db)
.into_iter()
.rev()
.filter_map(|it| it.name(db))
.chain(c.name(db))
.join("::");
println!("Const eval for {full_name} failed due {e:?}");
}
fail += 1;
}
eprintln!("{:<20} {}", "Const evaluation:", sw.elapsed());
eprintln!("Failed const evals: {fail} ({}%)", fail * 100 / all);
report_metric("failed const evals", fail, "#");
}

fn run_mir_lowering(&self, db: &RootDatabase, funcs: &[Function], verbosity: Verbosity) {
let mut sw = self.stop_watch();
let all = funcs.len() as u64;
let mut fail = 0;
let mut h: HashMap<String, usize> = HashMap::new();
for f in funcs {
let f = FunctionId::from(*f);
let Err(e) = db.mir_body(f.into()) else {
let Err(e) = db.mir_body(FunctionId::from(*f).into()) else {
continue;
};
let es = format!("{:?}", e);
*h.entry(es).or_default() += 1;
if verbosity.is_spammy() {
let full_name = f
.module(db)
.path_to_root(db)
.into_iter()
.rev()
.filter_map(|it| it.name(db))
.chain(Some(f.name(db)))
.join("::");
println!("Mir body for {full_name} failed due {e:?}");
}
fail += 1;
}
let h = h.into_iter().sorted_by_key(|x| x.1).collect::<Vec<_>>();
eprintln!("Mir failed reasons: {:#?}", h);
eprintln!("{:<20} {}", "MIR lowering:", sw.elapsed());
eprintln!("Mir failed bodies: {fail} ({}%)", fail * 100 / all);
report_metric("mir failed bodies", fail, "#");
}

fn run_inference(
Expand Down
6 changes: 3 additions & 3 deletions crates/rust-analyzer/src/cli/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ xflags::xflags! {
optional --memory-usage
/// Print the total length of all source and macro files (whitespace is not counted).
optional --source-stats
/// Print the number of bodies that fail to lower to mir, in addition to failed reasons.
optional --mir-stats
/// Only type check, skip lowering to mir
optional --skip-mir-stats

/// Only analyze items matching this path.
optional -o, --only path: String
Expand Down Expand Up @@ -171,7 +171,7 @@ pub struct AnalysisStats {
pub parallel: bool,
pub memory_usage: bool,
pub source_stats: bool,
pub mir_stats: bool,
pub skip_mir_stats: bool,
pub only: Option<String>,
pub with_deps: bool,
pub no_sysroot: bool,
Expand Down

0 comments on commit e5c7228

Please sign in to comment.