]> git.lizzy.rs Git - rust.git/blob - crates/rust-analyzer/src/integrated_benchmarks.rs
Merge #9079
[rust.git] / crates / rust-analyzer / src / integrated_benchmarks.rs
1 //! Fully integrated benchmarks for rust-analyzer, which load real cargo
2 //! projects.
3 //!
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.
8 //!
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.
12
13 use std::{convert::TryFrom, sync::Arc};
14
15 use ide::{Change, CompletionConfig, FilePosition, TextSize};
16 use ide_db::helpers::{
17     insert_use::{ImportGranularity, InsertUseConfig},
18     SnippetCap,
19 };
20 use test_utils::project_root;
21 use vfs::{AbsPathBuf, VfsPath};
22
23 use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig};
24
25 #[test]
26 fn integrated_highlighting_benchmark() {
27     if std::env::var("RUN_SLOW_BENCHES").is_err() {
28         return;
29     }
30
31     // Load rust-analyzer itself.
32     let workspace_to_load = project_root();
33     let file = "./crates/ide_db/src/apply_change.rs";
34
35     let cargo_config = Default::default();
36     let load_cargo_config = LoadCargoConfig {
37         load_out_dirs_from_check: true,
38         wrap_rustc: false,
39         with_proc_macro: false,
40     };
41
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()
45     };
46
47     let file_id = {
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))
51     };
52
53     {
54         let _it = stdx::timeit("initial");
55         let analysis = host.analysis();
56         analysis.highlight_as_html(file_id, false).unwrap();
57     }
58
59     profile::init_from("*>100");
60     // let _s = profile::heartbeat_span();
61
62     {
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);
69     }
70
71     {
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();
76     }
77 }
78
79 #[test]
80 fn integrated_completion_benchmark() {
81     if std::env::var("RUN_SLOW_BENCHES").is_err() {
82         return;
83     }
84
85     // Load rust-analyzer itself.
86     let workspace_to_load = project_root();
87     let file = "./crates/hir/src/lib.rs";
88
89     let cargo_config = Default::default();
90     let load_cargo_config = LoadCargoConfig {
91         load_out_dirs_from_check: true,
92         wrap_rustc: false,
93         with_proc_macro: false,
94     };
95
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()
99     };
100
101     let file_id = {
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))
105     };
106
107     {
108         let _it = stdx::timeit("initial");
109         let analysis = host.analysis();
110         analysis.highlight_as_html(file_id, false).unwrap();
111     }
112
113     profile::init_from("*>5");
114     // let _s = profile::heartbeat_span();
115
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)")
121                 + "sel".len();
122         let mut change = Change::new();
123         change.change_file(file_id, Some(Arc::new(text)));
124         host.apply_change(change);
125         completion_offset
126     };
127
128     {
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             enable_self_on_the_fly: true,
136             add_call_parenthesis: true,
137             add_call_argument_snippets: true,
138             snippet_cap: SnippetCap::new(true),
139             insert_use: InsertUseConfig {
140                 granularity: ImportGranularity::Crate,
141                 prefix_kind: hir::PrefixKind::ByCrate,
142                 enforce_granularity: true,
143                 group: true,
144             },
145         };
146         let position =
147             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
148         analysis.completions(&config, position).unwrap();
149     }
150
151     let completion_offset = {
152         let _it = stdx::timeit("change");
153         let mut text = host.analysis().file_text(file_id).unwrap().to_string();
154         let completion_offset =
155             patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)")
156                 + "self.".len();
157         let mut change = Change::new();
158         change.change_file(file_id, Some(Arc::new(text)));
159         host.apply_change(change);
160         completion_offset
161     };
162
163     {
164         let _p = profile::span("dot completion");
165         let _span = profile::cpu_span();
166         let analysis = host.analysis();
167         let config = CompletionConfig {
168             enable_postfix_completions: true,
169             enable_imports_on_the_fly: true,
170             enable_self_on_the_fly: true,
171             add_call_parenthesis: true,
172             add_call_argument_snippets: true,
173             snippet_cap: SnippetCap::new(true),
174             insert_use: InsertUseConfig {
175                 granularity: ImportGranularity::Crate,
176                 prefix_kind: hir::PrefixKind::ByCrate,
177                 enforce_granularity: true,
178                 group: true,
179             },
180         };
181         let position =
182             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
183         analysis.completions(&config, position).unwrap();
184     }
185 }
186
187 fn patch(what: &mut String, from: &str, to: &str) -> usize {
188     let idx = what.find(from).unwrap();
189     *what = what.replacen(from, to, 1);
190     idx
191 }