]> git.lizzy.rs Git - rust.git/blob - crates/rust-analyzer/src/integrated_benchmarks.rs
3dcbe397ad83bb838236e23536f95f110754085e
[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::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap};
17 use test_utils::project_root;
18 use vfs::{AbsPathBuf, VfsPath};
19
20 use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig};
21
22 #[test]
23 fn integrated_highlighting_benchmark() {
24     if std::env::var("RUN_SLOW_BENCHES").is_err() {
25         return;
26     }
27
28     // Load rust-analyzer itself.
29     let workspace_to_load = project_root();
30     let file = "./crates/ide_db/src/apply_change.rs";
31
32     let cargo_config = Default::default();
33     let load_cargo_config = LoadCargoConfig {
34         load_out_dirs_from_check: true,
35         wrap_rustc: false,
36         with_proc_macro: false,
37     };
38
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()
42     };
43
44     let file_id = {
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))
48     };
49
50     {
51         let _it = stdx::timeit("initial");
52         let analysis = host.analysis();
53         analysis.highlight_as_html(file_id, false).unwrap();
54     }
55
56     profile::init_from("*>100");
57     // let _s = profile::heartbeat_span();
58
59     {
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);
66     }
67
68     {
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();
73     }
74 }
75
76 #[test]
77 fn integrated_completion_benchmark() {
78     if std::env::var("RUN_SLOW_BENCHES").is_err() {
79         return;
80     }
81
82     // Load rust-analyzer itself.
83     let workspace_to_load = project_root();
84     let file = "./crates/hir/src/lib.rs";
85
86     let cargo_config = Default::default();
87     let load_cargo_config = LoadCargoConfig {
88         load_out_dirs_from_check: true,
89         wrap_rustc: false,
90         with_proc_macro: false,
91     };
92
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()
96     };
97
98     let file_id = {
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))
102     };
103
104     {
105         let _it = stdx::timeit("initial");
106         let analysis = host.analysis();
107         analysis.highlight_as_html(file_id, false).unwrap();
108     }
109
110     profile::init_from("*>5");
111     // let _s = profile::heartbeat_span();
112
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)")
118                 + "sel".len();
119         let mut change = Change::new();
120         change.change_file(file_id, Some(Arc::new(text)));
121         host.apply_change(change);
122         completion_offset
123     };
124
125     {
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,
138                 group: true,
139             },
140         };
141         let position =
142             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
143         analysis.completions(&config, position).unwrap();
144     }
145
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)")
151                 + "self.".len();
152         let mut change = Change::new();
153         change.change_file(file_id, Some(Arc::new(text)));
154         host.apply_change(change);
155         completion_offset
156     };
157
158     {
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,
171                 group: true,
172             },
173         };
174         let position =
175             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
176         analysis.completions(&config, position).unwrap();
177     }
178 }
179
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);
183     idx
184 }