1 //! Fully integrated benchmarks for rust-analyzer, which load real cargo
4 //! The benchmark here is used to debug specific performance regressions. If you
5 //! notice that, eg, completion is slow in some specific case, you can modify
6 //! code here exercise this specific completion, and thus have a fast
7 //! edit/compile/test cycle.
9 //! Note that "Rust Analyzer: Run" action does not allow running a single test
10 //! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line"
11 //! which you can use to paste the command in terminal and add `--release` manually.
13 use std::{convert::TryFrom, sync::Arc};
15 use ide::{Change, CompletionConfig, FilePosition, TextSize};
16 use ide_db::helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap};
17 use test_utils::project_root;
18 use vfs::{AbsPathBuf, VfsPath};
20 use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig};
23 fn integrated_highlighting_benchmark() {
24 if std::env::var("RUN_SLOW_BENCHES").is_err() {
28 // Load rust-analyzer itself.
29 let workspace_to_load = project_root();
30 let file = "./crates/ide_db/src/apply_change.rs";
32 let cargo_config = Default::default();
33 let load_cargo_config = LoadCargoConfig {
34 load_out_dirs_from_check: true,
36 with_proc_macro: false,
39 let (mut host, vfs, _proc_macro) = {
40 let _it = stdx::timeit("workspace loading");
41 load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
45 let file = workspace_to_load.join(file);
46 let path = VfsPath::from(AbsPathBuf::assert(file));
47 vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path))
51 let _it = stdx::timeit("initial");
52 let analysis = host.analysis();
53 analysis.highlight_as_html(file_id, false).unwrap();
56 profile::init_from("*>100");
57 // let _s = profile::heartbeat_span();
60 let _it = stdx::timeit("change");
61 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
62 text.push_str("\npub fn _dummy() {}\n");
63 let mut change = Change::new();
64 change.change_file(file_id, Some(Arc::new(text)));
65 host.apply_change(change);
69 let _it = stdx::timeit("after change");
70 let _span = profile::cpu_span();
71 let analysis = host.analysis();
72 analysis.highlight_as_html(file_id, false).unwrap();
77 fn integrated_completion_benchmark() {
78 if std::env::var("RUN_SLOW_BENCHES").is_err() {
82 // Load rust-analyzer itself.
83 let workspace_to_load = project_root();
84 let file = "./crates/hir/src/lib.rs";
86 let cargo_config = Default::default();
87 let load_cargo_config = LoadCargoConfig {
88 load_out_dirs_from_check: true,
90 with_proc_macro: false,
93 let (mut host, vfs, _proc_macro) = {
94 let _it = stdx::timeit("workspace loading");
95 load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
99 let file = workspace_to_load.join(file);
100 let path = VfsPath::from(AbsPathBuf::assert(file));
101 vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path))
105 let _it = stdx::timeit("initial");
106 let analysis = host.analysis();
107 analysis.highlight_as_html(file_id, false).unwrap();
110 profile::init_from("*>5");
111 // let _s = profile::heartbeat_span();
113 let completion_offset = {
114 let _it = stdx::timeit("change");
115 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
116 let completion_offset =
117 patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)")
119 let mut change = Change::new();
120 change.change_file(file_id, Some(Arc::new(text)));
121 host.apply_change(change);
126 let _it = stdx::timeit("unqualified path completion");
127 let _span = profile::cpu_span();
128 let analysis = host.analysis();
129 let config = CompletionConfig {
130 enable_postfix_completions: true,
131 enable_imports_on_the_fly: true,
132 add_call_parenthesis: true,
133 add_call_argument_snippets: true,
134 snippet_cap: SnippetCap::new(true),
135 insert_use: InsertUseConfig {
136 merge: Some(MergeBehavior::Full),
137 prefix_kind: hir::PrefixKind::ByCrate,
142 FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
143 analysis.completions(&config, position).unwrap();
146 let completion_offset = {
147 let _it = stdx::timeit("change");
148 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
149 let completion_offset =
150 patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)")
152 let mut change = Change::new();
153 change.change_file(file_id, Some(Arc::new(text)));
154 host.apply_change(change);
159 let _it = stdx::timeit("dot completion");
160 let _span = profile::cpu_span();
161 let analysis = host.analysis();
162 let config = CompletionConfig {
163 enable_postfix_completions: true,
164 enable_imports_on_the_fly: true,
165 add_call_parenthesis: true,
166 add_call_argument_snippets: true,
167 snippet_cap: SnippetCap::new(true),
168 insert_use: InsertUseConfig {
169 merge: Some(MergeBehavior::Full),
170 prefix_kind: hir::PrefixKind::ByCrate,
175 FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
176 analysis.completions(&config, position).unwrap();
180 fn patch(what: &mut String, from: &str, to: &str) -> usize {
181 let idx = what.find(from).unwrap();
182 *what = what.replacen(from, to, 1);