1 //! Benchmark operations like highlighting or goto definition.
3 use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant};
5 use anyhow::{bail, format_err, Result};
7 Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol,
11 salsa::{Database, Durability},
18 use crate::cli::{load_cargo::load_cargo, print_memory_usage, Verbosity};
23 pub memory_usage: bool,
24 pub load_output_dirs: bool,
25 pub with_proc_macro: bool,
29 Highlight { path: AbsPathBuf },
40 impl FromStr for Position {
41 type Err = anyhow::Error;
42 fn from_str(s: &str) -> Result<Self> {
43 let mut split = s.rsplitn(3, ':');
44 match (split.next(), split.next(), split.next()) {
45 (Some(column), Some(line), Some(path)) => {
46 let path = env::current_dir().unwrap().join(path);
47 let path = AbsPathBuf::assert(path);
48 Ok(Position { path, line: line.parse()?, column: column.parse()? })
50 _ => bail!("position should be in file:line:column format: {:?}", s),
56 pub fn run(self, verbosity: Verbosity) -> Result<()> {
59 let start = Instant::now();
61 let (mut host, vfs) = load_cargo(&self.path, self.load_output_dirs, self.with_proc_macro)?;
62 eprintln!("{:?}\n", start.elapsed());
65 let path = match &self.what {
66 BenchWhat::Highlight { path } => path,
67 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => &pos.path,
69 let path = path.clone().into();
70 vfs.file_id(&path).ok_or_else(|| format_err!("Can't find {}", path))?
74 BenchWhat::Highlight { .. } => {
75 let res = do_work(&mut host, file_id, |analysis| {
76 analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap();
77 analysis.highlight_as_html(file_id, false).unwrap()
79 if verbosity.is_verbose() {
80 println!("\n{}", res);
83 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => {
84 let is_completion = matches!(self.what, BenchWhat::Complete(..));
88 .file_line_index(file_id)?
89 .offset(LineCol { line: pos.line - 1, col_utf16: pos.column });
90 let file_position = FilePosition { file_id, offset };
93 let options = CompletionConfig {
94 enable_postfix_completions: true,
95 enable_autoimport_completions: true,
96 add_call_parenthesis: true,
97 add_call_argument_snippets: true,
98 snippet_cap: SnippetCap::new(true),
101 let res = do_work(&mut host, file_id, |analysis| {
102 analysis.completions(&options, file_position)
104 if verbosity.is_verbose() {
105 println!("\n{:#?}", res);
108 let res = do_work(&mut host, file_id, |analysis| {
109 analysis.goto_definition(file_position)
111 if verbosity.is_verbose() {
112 println!("\n{:#?}", res);
118 if self.memory_usage {
119 print_memory_usage(host, vfs);
126 fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, work: F) -> T {
128 let start = Instant::now();
129 eprint!("from scratch: ");
130 work(&host.analysis());
131 eprintln!("{:?}", start.elapsed());
134 let start = Instant::now();
135 eprint!("no change: ");
136 work(&host.analysis());
137 eprintln!("{:?}", start.elapsed());
140 let start = Instant::now();
141 eprint!("trivial change: ");
142 host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::LOW);
143 work(&host.analysis());
144 eprintln!("{:?}", start.elapsed());
147 let start = Instant::now();
148 eprint!("comment change: ");
150 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
151 text.push_str("\n/* Hello world */\n");
152 let mut change = Change::new();
153 change.change_file(file_id, Some(Arc::new(text)));
154 host.apply_change(change);
156 work(&host.analysis());
157 eprintln!("{:?}", start.elapsed());
160 let start = Instant::now();
161 eprint!("item change: ");
163 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
164 text.push_str("\npub fn _dummy() {}\n");
165 let mut change = Change::new();
166 change.change_file(file_id, Some(Arc::new(text)));
167 host.apply_change(change);
169 work(&host.analysis());
170 eprintln!("{:?}", start.elapsed());
173 let start = Instant::now();
174 eprint!("const change: ");
175 host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::HIGH);
176 let res = work(&host.analysis());
177 eprintln!("{:?}", start.elapsed());