diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-06-16 17:45:30 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-06-16 17:45:30 +0100 |
commit | 924d4d7ca8bce948b8cbb30ef6da17354e48bad3 (patch) | |
tree | 022742121ea273b6e90f6fbfa342660f46e9f68e /crates/ra_cli | |
parent | b81caed43f1886024ededad41a1baa8a03f1d2f4 (diff) | |
parent | 6314e62cfb06ea7bbe5f530f2824010be0ffa4c7 (diff) |
Merge #1411
1411: add analysis-bench to benchmark incremental analysis r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_cli')
-rw-r--r-- | crates/ra_cli/src/analysis_bench.rs | 92 | ||||
-rw-r--r-- | crates/ra_cli/src/analysis_stats.rs | 19 | ||||
-rw-r--r-- | crates/ra_cli/src/main.rs | 47 |
3 files changed, 149 insertions, 9 deletions
diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_cli/src/analysis_bench.rs new file mode 100644 index 000000000..33d472838 --- /dev/null +++ b/crates/ra_cli/src/analysis_bench.rs | |||
@@ -0,0 +1,92 @@ | |||
1 | use std::{ | ||
2 | path::{PathBuf, Path}, | ||
3 | time::Instant, | ||
4 | }; | ||
5 | |||
6 | use ra_db::{SourceDatabase, salsa::Database}; | ||
7 | use ra_ide_api::{AnalysisHost, Analysis, LineCol, FilePosition}; | ||
8 | |||
9 | use crate::Result; | ||
10 | |||
11 | pub(crate) enum Op { | ||
12 | Highlight { path: PathBuf }, | ||
13 | Complete { path: PathBuf, line: u32, column: u32 }, | ||
14 | } | ||
15 | |||
16 | pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { | ||
17 | let start = Instant::now(); | ||
18 | eprint!("loading: "); | ||
19 | let (host, roots) = ra_batch::load_cargo(path)?; | ||
20 | let db = host.raw_database(); | ||
21 | eprintln!("{:?}\n", start.elapsed()); | ||
22 | |||
23 | let file_id = { | ||
24 | let path = match &op { | ||
25 | Op::Highlight { path } => path, | ||
26 | Op::Complete { path, .. } => path, | ||
27 | }; | ||
28 | let path = std::env::current_dir()?.join(path).canonicalize()?; | ||
29 | roots | ||
30 | .iter() | ||
31 | .find_map(|(source_root_id, project_root)| { | ||
32 | if project_root.is_member() { | ||
33 | for (rel_path, file_id) in &db.source_root(*source_root_id).files { | ||
34 | let abs_path = rel_path.to_path(project_root.path()); | ||
35 | if abs_path == path { | ||
36 | return Some(*file_id); | ||
37 | } | ||
38 | } | ||
39 | } | ||
40 | None | ||
41 | }) | ||
42 | .ok_or_else(|| format!("Can't find {:?}", path))? | ||
43 | }; | ||
44 | |||
45 | match op { | ||
46 | Op::Highlight { .. } => { | ||
47 | let res = do_work(&host, |analysis| { | ||
48 | analysis.diagnostics(file_id).unwrap(); | ||
49 | analysis.highlight_as_html(file_id, false).unwrap() | ||
50 | }); | ||
51 | if verbose { | ||
52 | println!("\n{}", res); | ||
53 | } | ||
54 | } | ||
55 | Op::Complete { line, column, .. } => { | ||
56 | let offset = host | ||
57 | .analysis() | ||
58 | .file_line_index(file_id) | ||
59 | .offset(LineCol { line, col_utf16: column }); | ||
60 | let file_postion = FilePosition { file_id, offset }; | ||
61 | |||
62 | let res = do_work(&host, |analysis| analysis.completions(file_postion)); | ||
63 | if verbose { | ||
64 | println!("\n{:#?}", res); | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | Ok(()) | ||
69 | } | ||
70 | |||
71 | fn do_work<F: Fn(&Analysis) -> T, T>(host: &AnalysisHost, work: F) -> T { | ||
72 | { | ||
73 | let start = Instant::now(); | ||
74 | eprint!("from scratch: "); | ||
75 | work(&host.analysis()); | ||
76 | eprintln!("{:?}", start.elapsed()); | ||
77 | } | ||
78 | { | ||
79 | let start = Instant::now(); | ||
80 | eprint!("no change: "); | ||
81 | work(&host.analysis()); | ||
82 | eprintln!("{:?}", start.elapsed()); | ||
83 | } | ||
84 | { | ||
85 | let start = Instant::now(); | ||
86 | eprint!("trivial change: "); | ||
87 | host.raw_database().salsa_runtime().next_revision(); | ||
88 | let res = work(&host.analysis()); | ||
89 | eprintln!("{:?}", start.elapsed()); | ||
90 | res | ||
91 | } | ||
92 | } | ||
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs index d76c37d84..ed98fc7f6 100644 --- a/crates/ra_cli/src/analysis_stats.rs +++ b/crates/ra_cli/src/analysis_stats.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use std::{collections::HashSet, time::Instant, fmt::Write}; | 1 | use std::{collections::HashSet, time::Instant, fmt::Write, path::Path}; |
2 | 2 | ||
3 | use ra_db::SourceDatabase; | 3 | use ra_db::SourceDatabase; |
4 | use ra_hir::{Crate, ModuleDef, Ty, ImplItem, HasSource}; | 4 | use ra_hir::{Crate, ModuleDef, Ty, ImplItem, HasSource}; |
@@ -6,20 +6,23 @@ use ra_syntax::AstNode; | |||
6 | 6 | ||
7 | use crate::Result; | 7 | use crate::Result; |
8 | 8 | ||
9 | pub fn run(verbose: bool, path: &str, only: Option<&str>) -> Result<()> { | 9 | pub fn run(verbose: bool, path: &Path, only: Option<&str>) -> Result<()> { |
10 | let db_load_time = Instant::now(); | 10 | let db_load_time = Instant::now(); |
11 | let (host, roots) = ra_batch::load_cargo(path.as_ref())?; | 11 | let (host, roots) = ra_batch::load_cargo(path)?; |
12 | let db = host.raw_database(); | 12 | let db = host.raw_database(); |
13 | println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed()); | 13 | println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed()); |
14 | let analysis_time = Instant::now(); | 14 | let analysis_time = Instant::now(); |
15 | let mut num_crates = 0; | 15 | let mut num_crates = 0; |
16 | let mut visited_modules = HashSet::new(); | 16 | let mut visited_modules = HashSet::new(); |
17 | let mut visit_queue = Vec::new(); | 17 | let mut visit_queue = Vec::new(); |
18 | for root in roots { | 18 | for (source_root_id, project_root) in roots { |
19 | for krate in Crate::source_root_crates(db, root) { | 19 | if project_root.is_member() { |
20 | num_crates += 1; | 20 | for krate in Crate::source_root_crates(db, source_root_id) { |
21 | let module = krate.root_module(db).expect("crate in source root without root module"); | 21 | num_crates += 1; |
22 | visit_queue.push(module); | 22 | let module = |
23 | krate.root_module(db).expect("crate in source root without root module"); | ||
24 | visit_queue.push(module); | ||
25 | } | ||
23 | } | 26 | } |
24 | } | 27 | } |
25 | println!("Crates in this dir: {}", num_crates); | 28 | println!("Crates in this dir: {}", num_crates); |
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index 1db98aec1..5adf8b096 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | mod analysis_stats; | 1 | mod analysis_stats; |
2 | mod analysis_bench; | ||
2 | 3 | ||
3 | use std::{io::Read, error::Error}; | 4 | use std::{io::Read, error::Error}; |
4 | 5 | ||
@@ -26,6 +27,27 @@ fn main() -> Result<()> { | |||
26 | .arg(Arg::with_name("only").short("o").takes_value(true)) | 27 | .arg(Arg::with_name("only").short("o").takes_value(true)) |
27 | .arg(Arg::with_name("path")), | 28 | .arg(Arg::with_name("path")), |
28 | ) | 29 | ) |
30 | .subcommand( | ||
31 | SubCommand::with_name("analysis-bench") | ||
32 | .arg(Arg::with_name("verbose").short("v").long("verbose")) | ||
33 | .arg( | ||
34 | Arg::with_name("highlight") | ||
35 | .long("highlight") | ||
36 | .takes_value(true) | ||
37 | .conflicts_with("complete") | ||
38 | .value_name("PATH") | ||
39 | .help("highlight this file"), | ||
40 | ) | ||
41 | .arg( | ||
42 | Arg::with_name("complete") | ||
43 | .long("complete") | ||
44 | .takes_value(true) | ||
45 | .conflicts_with("highlight") | ||
46 | .value_name("PATH:LINE:COLUMN") | ||
47 | .help("compute completions at this location"), | ||
48 | ) | ||
49 | .arg(Arg::with_name("path").value_name("PATH").help("project to analyze")), | ||
50 | ) | ||
29 | .get_matches(); | 51 | .get_matches(); |
30 | match matches.subcommand() { | 52 | match matches.subcommand() { |
31 | ("parse", Some(matches)) => { | 53 | ("parse", Some(matches)) => { |
@@ -51,7 +73,25 @@ fn main() -> Result<()> { | |||
51 | let verbose = matches.is_present("verbose"); | 73 | let verbose = matches.is_present("verbose"); |
52 | let path = matches.value_of("path").unwrap_or(""); | 74 | let path = matches.value_of("path").unwrap_or(""); |
53 | let only = matches.value_of("only"); | 75 | let only = matches.value_of("only"); |
54 | analysis_stats::run(verbose, path, only)?; | 76 | analysis_stats::run(verbose, path.as_ref(), only)?; |
77 | } | ||
78 | ("analysis-bench", Some(matches)) => { | ||
79 | let verbose = matches.is_present("verbose"); | ||
80 | let path = matches.value_of("path").unwrap_or(""); | ||
81 | let op = if let Some(path) = matches.value_of("highlight") { | ||
82 | analysis_bench::Op::Highlight { path: path.into() } | ||
83 | } else if let Some(path_line_col) = matches.value_of("complete") { | ||
84 | let (path_line, column) = rsplit_at_char(path_line_col, ':')?; | ||
85 | let (path, line) = rsplit_at_char(path_line, ':')?; | ||
86 | analysis_bench::Op::Complete { | ||
87 | path: path.into(), | ||
88 | line: line.parse()?, | ||
89 | column: column.parse()?, | ||
90 | } | ||
91 | } else { | ||
92 | panic!("either --highlight or --complete must be set") | ||
93 | }; | ||
94 | analysis_bench::run(verbose, path.as_ref(), op)?; | ||
55 | } | 95 | } |
56 | _ => unreachable!(), | 96 | _ => unreachable!(), |
57 | } | 97 | } |
@@ -68,3 +108,8 @@ fn read_stdin() -> Result<String> { | |||
68 | std::io::stdin().read_to_string(&mut buff)?; | 108 | std::io::stdin().read_to_string(&mut buff)?; |
69 | Ok(buff) | 109 | Ok(buff) |
70 | } | 110 | } |
111 | |||
112 | fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> { | ||
113 | let idx = s.rfind(":").ok_or_else(|| format!("no `{}` in {}", c, s))?; | ||
114 | Ok((&s[..idx], &s[idx + 1..])) | ||
115 | } | ||