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::{
17 insert_use::{ImportGranularity, InsertUseConfig},
20 use test_utils::project_root;
21 use vfs::{AbsPathBuf, VfsPath};
23 use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig};
26 fn integrated_highlighting_benchmark() {
27 if std::env::var("RUN_SLOW_BENCHES").is_err() {
31 // Load rust-analyzer itself.
32 let workspace_to_load = project_root();
33 let file = "./crates/ide_db/src/apply_change.rs";
35 let cargo_config = Default::default();
36 let load_cargo_config = LoadCargoConfig {
37 load_out_dirs_from_check: true,
39 with_proc_macro: false,
42 let (mut host, vfs, _proc_macro) = {
43 let _it = stdx::timeit("workspace loading");
44 load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
48 let file = workspace_to_load.join(file);
49 let path = VfsPath::from(AbsPathBuf::assert(file));
50 vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path))
54 let _it = stdx::timeit("initial");
55 let analysis = host.analysis();
56 analysis.highlight_as_html(file_id, false).unwrap();
59 profile::init_from("*>100");
60 // let _s = profile::heartbeat_span();
63 let _it = stdx::timeit("change");
64 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
65 text.push_str("\npub fn _dummy() {}\n");
66 let mut change = Change::new();
67 change.change_file(file_id, Some(Arc::new(text)));
68 host.apply_change(change);
72 let _it = stdx::timeit("after change");
73 let _span = profile::cpu_span();
74 let analysis = host.analysis();
75 analysis.highlight_as_html(file_id, false).unwrap();
80 fn integrated_completion_benchmark() {
81 if std::env::var("RUN_SLOW_BENCHES").is_err() {
85 // Load rust-analyzer itself.
86 let workspace_to_load = project_root();
87 let file = "./crates/hir/src/lib.rs";
89 let cargo_config = Default::default();
90 let load_cargo_config = LoadCargoConfig {
91 load_out_dirs_from_check: true,
93 with_proc_macro: false,
96 let (mut host, vfs, _proc_macro) = {
97 let _it = stdx::timeit("workspace loading");
98 load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
102 let file = workspace_to_load.join(file);
103 let path = VfsPath::from(AbsPathBuf::assert(file));
104 vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path))
108 let _it = stdx::timeit("initial");
109 let analysis = host.analysis();
110 analysis.highlight_as_html(file_id, false).unwrap();
113 profile::init_from("*>5");
114 // let _s = profile::heartbeat_span();
116 let completion_offset = {
117 let _it = stdx::timeit("change");
118 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
119 let completion_offset =
120 patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)")
122 let mut change = Change::new();
123 change.change_file(file_id, Some(Arc::new(text)));
124 host.apply_change(change);
129 let _p = profile::span("unqualified path completion");
130 let _span = profile::cpu_span();
131 let analysis = host.analysis();
132 let config = CompletionConfig {
133 enable_postfix_completions: true,
134 enable_imports_on_the_fly: true,
135 add_call_parenthesis: true,
136 add_call_argument_snippets: true,
137 snippet_cap: SnippetCap::new(true),
138 insert_use: InsertUseConfig {
139 granularity: ImportGranularity::Crate,
140 prefix_kind: hir::PrefixKind::ByCrate,
141 enforce_granularity: true,
146 FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
147 analysis.completions(&config, position).unwrap();
150 let completion_offset = {
151 let _it = stdx::timeit("change");
152 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
153 let completion_offset =
154 patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)")
156 let mut change = Change::new();
157 change.change_file(file_id, Some(Arc::new(text)));
158 host.apply_change(change);
163 let _p = profile::span("dot completion");
164 let _span = profile::cpu_span();
165 let analysis = host.analysis();
166 let config = CompletionConfig {
167 enable_postfix_completions: true,
168 enable_imports_on_the_fly: true,
169 add_call_parenthesis: true,
170 add_call_argument_snippets: true,
171 snippet_cap: SnippetCap::new(true),
172 insert_use: InsertUseConfig {
173 granularity: ImportGranularity::Crate,
174 prefix_kind: hir::PrefixKind::ByCrate,
175 enforce_granularity: true,
180 FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
181 analysis.completions(&config, position).unwrap();
185 fn patch(what: &mut String, from: &str, to: &str) -> usize {
186 let idx = what.find(from).unwrap();
187 *what = what.replacen(from, to, 1);