Can be used like this: ``` $ cargo run --release -p ra_cli -- \ analysis-bench ../chalk/ \ --complete ../chalk/chalk-engine/src/logic.rs:94:0 loading: 225.970093ms from scratch: 8.492373325s no change: 445.265µs trivial change: 95.631242ms ``` Or like this: ``` $ cargo run --release -p ra_cli -- \ analysis-bench ../chalk/ \ --highlight ../chalk/chalk-engine/src/logic.rs loading: 209.873484ms from scratch: 9.504916942s no change: 7.731119ms trivial change: 124.984039ms ``` "from scratch" includes initial analysis of the relevant bits of the project "no change" just asks the same question for the second time. It measures overhead on assembling the answer outside of salsa. "trivial change" doesn't do an actual salsa change, it just advances the revision. This test how fast is salsa at validating things.
118 lines
4.0 KiB
Rust
118 lines
4.0 KiB
Rust
use std::{collections::HashSet, time::Instant, fmt::Write, path::Path};
|
|
|
|
use ra_db::SourceDatabase;
|
|
use ra_hir::{Crate, ModuleDef, Ty, ImplItem, HasSource};
|
|
use ra_syntax::AstNode;
|
|
|
|
use crate::Result;
|
|
|
|
pub fn run(verbose: bool, path: &Path, only: Option<&str>) -> Result<()> {
|
|
let db_load_time = Instant::now();
|
|
let (host, roots) = ra_batch::load_cargo(path)?;
|
|
let db = host.raw_database();
|
|
println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed());
|
|
let analysis_time = Instant::now();
|
|
let mut num_crates = 0;
|
|
let mut visited_modules = HashSet::new();
|
|
let mut visit_queue = Vec::new();
|
|
for (source_root_id, project_root) in roots {
|
|
if project_root.is_member() {
|
|
for krate in Crate::source_root_crates(db, source_root_id) {
|
|
num_crates += 1;
|
|
let module =
|
|
krate.root_module(db).expect("crate in source root without root module");
|
|
visit_queue.push(module);
|
|
}
|
|
}
|
|
}
|
|
println!("Crates in this dir: {}", num_crates);
|
|
let mut num_decls = 0;
|
|
let mut funcs = 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);
|
|
}
|
|
}
|
|
|
|
for impl_block in module.impl_blocks(db) {
|
|
for item in impl_block.items(db) {
|
|
num_decls += 1;
|
|
if let ImplItem::Method(f) = item {
|
|
funcs.push(f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
println!("Total modules found: {}", visited_modules.len());
|
|
println!("Total declarations: {}", num_decls);
|
|
println!("Total functions: {}", funcs.len());
|
|
let bar = indicatif::ProgressBar::with_draw_target(
|
|
funcs.len() as u64,
|
|
indicatif::ProgressDrawTarget::stderr_nohz(),
|
|
);
|
|
bar.set_style(
|
|
indicatif::ProgressStyle::default_bar().template("{wide_bar} {pos}/{len}\n{msg}"),
|
|
);
|
|
bar.tick();
|
|
let mut num_exprs = 0;
|
|
let mut num_exprs_unknown = 0;
|
|
let mut num_exprs_partially_unknown = 0;
|
|
for f in funcs {
|
|
let name = f.name(db);
|
|
let mut msg = format!("processing: {}", name);
|
|
if verbose {
|
|
let src = f.source(db);
|
|
let original_file = src.file_id.original_file(db);
|
|
let path = db.file_relative_path(original_file);
|
|
let syntax_range = src.ast.syntax().range();
|
|
write!(msg, " ({:?} {})", path, syntax_range).unwrap();
|
|
}
|
|
bar.set_message(&msg);
|
|
if let Some(only_name) = only {
|
|
if name.to_string() != only_name {
|
|
continue;
|
|
}
|
|
}
|
|
let body = f.body(db);
|
|
let inference_result = f.infer(db);
|
|
for (expr_id, _) in body.exprs() {
|
|
let ty = &inference_result[expr_id];
|
|
num_exprs += 1;
|
|
if let Ty::Unknown = ty {
|
|
num_exprs_unknown += 1;
|
|
} else {
|
|
let mut is_partially_unknown = false;
|
|
ty.walk(&mut |ty| {
|
|
if let Ty::Unknown = ty {
|
|
is_partially_unknown = true;
|
|
}
|
|
});
|
|
if is_partially_unknown {
|
|
num_exprs_partially_unknown += 1;
|
|
}
|
|
}
|
|
}
|
|
bar.inc(1);
|
|
}
|
|
bar.finish_and_clear();
|
|
println!("Total expressions: {}", num_exprs);
|
|
println!(
|
|
"Expressions of unknown type: {} ({}%)",
|
|
num_exprs_unknown,
|
|
(num_exprs_unknown * 100 / num_exprs)
|
|
);
|
|
println!(
|
|
"Expressions of partially unknown type: {} ({}%)",
|
|
num_exprs_partially_unknown,
|
|
(num_exprs_partially_unknown * 100 / num_exprs)
|
|
);
|
|
println!("Analysis: {:?}", analysis_time.elapsed());
|
|
Ok(())
|
|
}
|