Skip to content

Commit 5c704f1

Browse files
bors[bot]matklad
andauthored
Merge #10088
10088: feat: improve CPU usage r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
2 parents bb1987b + 53d2050 commit 5c704f1

File tree

4 files changed

+99
-99
lines changed

4 files changed

+99
-99
lines changed

crates/ide/src/prime_caches.rs

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,26 @@ use ide_db::base_db::SourceDatabase;
88

99
use crate::RootDatabase;
1010

11+
/// We started indexing a crate.
1112
#[derive(Debug)]
12-
pub enum PrimeCachesProgress {
13-
Started,
14-
/// We started indexing a crate.
15-
StartedOnCrate {
16-
on_crate: String,
17-
n_done: usize,
18-
n_total: usize,
19-
},
20-
/// We finished indexing all crates.
21-
Finished,
13+
pub struct PrimeCachesProgress {
14+
pub on_crate: String,
15+
pub n_done: usize,
16+
pub n_total: usize,
2217
}
2318

2419
pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress) + Sync)) {
2520
let _p = profile::span("prime_caches");
2621
let graph = db.crate_graph();
2722
let topo = &graph.crates_in_topological_order();
2823

29-
cb(PrimeCachesProgress::Started);
30-
// Take care to emit the finish signal even when the computation is canceled.
31-
let _d = stdx::defer(|| cb(PrimeCachesProgress::Finished));
32-
3324
// FIXME: This would be easy to parallelize, since it's in the ideal ordering for that.
3425
// Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks
3526
// cancellation, so we cannot use rayon.
3627
for (i, &crate_id) in topo.iter().enumerate() {
3728
let crate_name = graph[crate_id].display_name.as_deref().unwrap_or_default().to_string();
3829

39-
cb(PrimeCachesProgress::StartedOnCrate {
40-
on_crate: crate_name,
41-
n_done: i,
42-
n_total: topo.len(),
43-
});
30+
cb(PrimeCachesProgress { on_crate: crate_name, n_done: i, n_total: topo.len() });
4431
db.crate_def_map(crate_id);
4532
db.import_map(crate_id);
4633
}

crates/rust-analyzer/src/main_loop.rs

Lines changed: 67 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ use std::{
88

99
use always_assert::always;
1010
use crossbeam_channel::{select, Receiver};
11-
use ide::{FileId, PrimeCachesProgress};
1211
use ide_db::base_db::{SourceDatabaseExt, VfsPath};
1312
use lsp_server::{Connection, Notification, Request};
1413
use lsp_types::notification::Notification as _;
15-
use vfs::ChangeKind;
14+
use vfs::{ChangeKind, FileId};
1615

1716
use crate::{
1817
config::Config,
@@ -67,6 +66,13 @@ pub(crate) enum Task {
6766
FetchBuildData(BuildDataProgress),
6867
}
6968

69+
#[derive(Debug)]
70+
pub(crate) enum PrimeCachesProgress {
71+
Begin,
72+
Report(ide::PrimeCachesProgress),
73+
End { cancelled: bool },
74+
}
75+
7076
impl fmt::Debug for Event {
7177
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7278
let debug_verbose_not = |not: &Notification, f: &mut fmt::Formatter| {
@@ -146,8 +152,10 @@ impl GlobalState {
146152
);
147153
}
148154

149-
self.fetch_workspaces_request();
150-
self.fetch_workspaces_if_needed();
155+
self.fetch_workspaces_queue.request_op();
156+
if self.fetch_workspaces_queue.should_start_op() {
157+
self.fetch_workspaces();
158+
}
151159

152160
while let Some(event) = self.next_event(&inbox) {
153161
if let Event::Lsp(lsp_server::Message::Notification(not)) = &event {
@@ -209,17 +217,17 @@ impl GlobalState {
209217
}
210218
}
211219
Task::PrimeCaches(progress) => match progress {
212-
PrimeCachesProgress::Started => prime_caches_progress.push(progress),
213-
PrimeCachesProgress::StartedOnCrate { .. } => {
220+
PrimeCachesProgress::Begin => prime_caches_progress.push(progress),
221+
PrimeCachesProgress::Report(_) => {
214222
match prime_caches_progress.last_mut() {
215-
Some(last @ PrimeCachesProgress::StartedOnCrate { .. }) => {
223+
Some(last @ PrimeCachesProgress::Report(_)) => {
216224
// Coalesce subsequent update events.
217225
*last = progress;
218226
}
219227
_ => prime_caches_progress.push(progress),
220228
}
221229
}
222-
PrimeCachesProgress::Finished => prime_caches_progress.push(progress),
230+
PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress),
223231
},
224232
Task::FetchWorkspace(progress) => {
225233
let (state, msg) = match progress {
@@ -228,14 +236,14 @@ impl GlobalState {
228236
(Progress::Report, Some(msg))
229237
}
230238
ProjectWorkspaceProgress::End(workspaces) => {
231-
self.fetch_workspaces_completed(workspaces);
239+
self.fetch_workspaces_queue.op_completed(workspaces);
232240

233241
let old = Arc::clone(&self.workspaces);
234242
self.switch_workspaces();
235243
let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
236244

237245
if self.config.run_build_scripts() && workspaces_updated {
238-
self.fetch_build_data_request()
246+
self.fetch_build_data_queue.request_op()
239247
}
240248

241249
(Progress::End, None)
@@ -251,7 +259,7 @@ impl GlobalState {
251259
(Some(Progress::Report), Some(msg))
252260
}
253261
BuildDataProgress::End(build_data_result) => {
254-
self.fetch_build_data_completed(build_data_result);
262+
self.fetch_build_data_queue.op_completed(build_data_result);
255263

256264
self.switch_workspaces();
257265

@@ -275,22 +283,28 @@ impl GlobalState {
275283
for progress in prime_caches_progress {
276284
let (state, message, fraction);
277285
match progress {
278-
PrimeCachesProgress::Started => {
286+
PrimeCachesProgress::Begin => {
279287
state = Progress::Begin;
280288
message = None;
281289
fraction = 0.0;
282290
}
283-
PrimeCachesProgress::StartedOnCrate { on_crate, n_done, n_total } => {
291+
PrimeCachesProgress::Report(report) => {
284292
state = Progress::Report;
285-
message = Some(format!("{}/{} ({})", n_done, n_total, on_crate));
286-
fraction = Progress::fraction(n_done, n_total);
293+
message = Some(format!(
294+
"{}/{} ({})",
295+
report.n_done, report.n_total, report.on_crate
296+
));
297+
fraction = Progress::fraction(report.n_done, report.n_total);
287298
}
288-
PrimeCachesProgress::Finished => {
299+
PrimeCachesProgress::End { cancelled } => {
289300
state = Progress::End;
290301
message = None;
291302
fraction = 1.0;
292303

293304
self.prime_caches_queue.op_completed(());
305+
if cancelled {
306+
self.prime_caches_queue.request_op();
307+
}
294308
}
295309
};
296310

@@ -413,26 +427,10 @@ impl GlobalState {
413427
for flycheck in &self.flycheck {
414428
flycheck.update();
415429
}
430+
self.prime_caches_queue.request_op();
416431
}
417432

418433
if !was_quiescent || state_changed {
419-
// Ensure that only one cache priming task can run at a time
420-
self.prime_caches_queue.request_op();
421-
if self.prime_caches_queue.should_start_op() {
422-
self.task_pool.handle.spawn_with_sender({
423-
let analysis = self.snapshot().analysis;
424-
move |sender| {
425-
let cb = |progress| {
426-
sender.send(Task::PrimeCaches(progress)).unwrap();
427-
};
428-
match analysis.prime_caches(cb) {
429-
Ok(()) => (),
430-
Err(_canceled) => (),
431-
}
432-
}
433-
});
434-
}
435-
436434
// Refresh semantic tokens if the client supports it.
437435
if self.config.semantic_tokens_refresh() {
438436
self.semantic_tokens_cache.lock().clear();
@@ -478,11 +476,43 @@ impl GlobalState {
478476
}
479477

480478
if self.config.cargo_autoreload() {
481-
self.fetch_workspaces_if_needed();
479+
if self.fetch_workspaces_queue.should_start_op() {
480+
self.fetch_workspaces();
481+
}
482+
}
483+
if self.fetch_build_data_queue.should_start_op() {
484+
self.fetch_build_data();
485+
}
486+
if self.prime_caches_queue.should_start_op() {
487+
self.task_pool.handle.spawn_with_sender({
488+
let analysis = self.snapshot().analysis;
489+
move |sender| {
490+
sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap();
491+
let res = analysis.prime_caches(|progress| {
492+
let report = PrimeCachesProgress::Report(progress);
493+
sender.send(Task::PrimeCaches(report)).unwrap();
494+
});
495+
sender
496+
.send(Task::PrimeCaches(PrimeCachesProgress::End {
497+
cancelled: res.is_err(),
498+
}))
499+
.unwrap();
500+
}
501+
});
482502
}
483-
self.fetch_build_data_if_needed();
484503

485-
self.report_new_status_if_needed();
504+
let status = self.current_status();
505+
if self.last_reported_status.as_ref() != Some(&status) {
506+
self.last_reported_status = Some(status.clone());
507+
508+
if let (lsp_ext::Health::Error, Some(message)) = (status.health, &status.message) {
509+
self.show_message(lsp_types::MessageType::Error, message.clone());
510+
}
511+
512+
if self.config.server_status_notification() {
513+
self.send_notification::<lsp_ext::ServerStatusNotification>(status);
514+
}
515+
}
486516

487517
let loop_duration = loop_start.elapsed();
488518
if loop_duration > Duration::from_millis(100) {
@@ -521,8 +551,7 @@ impl GlobalState {
521551

522552
RequestDispatcher { req: Some(req), global_state: self }
523553
.on_sync_mut::<lsp_ext::ReloadWorkspace>(|s, ()| {
524-
s.fetch_workspaces_request();
525-
s.fetch_workspaces_if_needed();
554+
s.fetch_workspaces_queue.request_op();
526555
Ok(())
527556
})?
528557
.on_sync_mut::<lsp_types::request::Shutdown>(|s, ()| {

crates/rust-analyzer/src/reload.rs

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ impl GlobalState {
4747
self.analysis_host.update_lru_capacity(self.config.lru_capacity());
4848
}
4949
if self.config.linked_projects() != old_config.linked_projects() {
50-
self.fetch_workspaces_request()
50+
self.fetch_workspaces_queue.request_op()
5151
} else if self.config.flycheck() != old_config.flycheck() {
5252
self.reload_flycheck();
5353
}
@@ -71,7 +71,7 @@ impl GlobalState {
7171
", "
7272
)
7373
);
74-
self.fetch_workspaces_request();
74+
self.fetch_workspaces_queue.request_op();
7575

7676
fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool {
7777
const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
@@ -109,7 +109,8 @@ impl GlobalState {
109109
false
110110
}
111111
}
112-
pub(crate) fn report_new_status_if_needed(&mut self) {
112+
113+
pub(crate) fn current_status(&self) -> lsp_ext::ServerStatusParams {
113114
let mut status = lsp_ext::ServerStatusParams {
114115
health: lsp_ext::Health::Ok,
115116
quiescent: self.is_quiescent(),
@@ -132,27 +133,10 @@ impl GlobalState {
132133
status.health = lsp_ext::Health::Error;
133134
status.message = Some(error)
134135
}
135-
136-
if self.last_reported_status.as_ref() != Some(&status) {
137-
self.last_reported_status = Some(status.clone());
138-
139-
if let (lsp_ext::Health::Error, Some(message)) = (status.health, &status.message) {
140-
self.show_message(lsp_types::MessageType::Error, message.clone());
141-
}
142-
143-
if self.config.server_status_notification() {
144-
self.send_notification::<lsp_ext::ServerStatusNotification>(status);
145-
}
146-
}
136+
status
147137
}
148138

149-
pub(crate) fn fetch_workspaces_request(&mut self) {
150-
self.fetch_workspaces_queue.request_op()
151-
}
152-
pub(crate) fn fetch_workspaces_if_needed(&mut self) {
153-
if !self.fetch_workspaces_queue.should_start_op() {
154-
return;
155-
}
139+
pub(crate) fn fetch_workspaces(&mut self) {
156140
tracing::info!("will fetch workspaces");
157141

158142
self.task_pool.handle.spawn_with_sender({
@@ -203,21 +187,8 @@ impl GlobalState {
203187
}
204188
});
205189
}
206-
pub(crate) fn fetch_workspaces_completed(
207-
&mut self,
208-
workspaces: Vec<anyhow::Result<ProjectWorkspace>>,
209-
) {
210-
self.fetch_workspaces_queue.op_completed(workspaces)
211-
}
212-
213-
pub(crate) fn fetch_build_data_request(&mut self) {
214-
self.fetch_build_data_queue.request_op();
215-
}
216-
pub(crate) fn fetch_build_data_if_needed(&mut self) {
217-
if !self.fetch_build_data_queue.should_start_op() {
218-
return;
219-
}
220190

191+
pub(crate) fn fetch_build_data(&mut self) {
221192
let workspaces = Arc::clone(&self.workspaces);
222193
let config = self.config.cargo();
223194
self.task_pool.handle.spawn_with_sender(move |sender| {
@@ -236,12 +207,6 @@ impl GlobalState {
236207
sender.send(Task::FetchBuildData(BuildDataProgress::End((workspaces, res)))).unwrap();
237208
});
238209
}
239-
pub(crate) fn fetch_build_data_completed(
240-
&mut self,
241-
build_data: (Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>),
242-
) {
243-
self.fetch_build_data_queue.op_completed(build_data)
244-
}
245210

246211
pub(crate) fn switch_workspaces(&mut self) {
247212
let _p = profile::span("GlobalState::switch_workspaces");

docs/dev/style.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,25 @@ if idx >= len {
257257

258258
**Rationale:** it's useful to see the invariant relied upon by the rest of the function clearly spelled out.
259259

260+
## Control Flow
261+
262+
As a special case of the previous rule, do not hide control flow inside functions, push it to the caller:
263+
264+
```rust
265+
// GOOD
266+
if cond {
267+
f()
268+
}
269+
270+
// BAD
271+
fn f() {
272+
if !cond {
273+
return;
274+
}
275+
...
276+
}
277+
```
278+
260279
## Assertions
261280

262281
Assert liberally.

0 commit comments

Comments
 (0)