aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-10-06 16:58:03 +0100
committerJonas Schievink <[email protected]>2020-10-12 12:35:01 +0100
commitcde7392ec809599e6337d91561971e08c8e06831 (patch)
tree061cc24d3af0d5189e5b1722a0f7416cc1a8bc34
parent518f6d772482c7c58e59081f340947087a9b4800 (diff)
Improve prime_caches and display its progress
-rw-r--r--crates/base_db/src/input.rs28
-rw-r--r--crates/ide/src/lib.rs8
-rw-r--r--crates/ide/src/prime_caches.rs43
-rw-r--r--crates/rust-analyzer/src/main_loop.rs42
-rw-r--r--crates/rust-analyzer/src/thread_pool.rs11
5 files changed, 119 insertions, 13 deletions
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index c330314d4..215ac4b41 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -221,6 +221,34 @@ impl CrateGraph {
221 deps.into_iter() 221 deps.into_iter()
222 } 222 }
223 223
224 /// Returns all crates in the graph, sorted in topological order (ie. dependencies of a crate
225 /// come before the crate itself).
226 pub fn crates_in_topological_order(&self) -> Vec<CrateId> {
227 let mut res = Vec::new();
228 let mut visited = FxHashSet::default();
229
230 for krate in self.arena.keys().copied() {
231 go(self, &mut visited, &mut res, krate);
232 }
233
234 return res;
235
236 fn go(
237 graph: &CrateGraph,
238 visited: &mut FxHashSet<CrateId>,
239 res: &mut Vec<CrateId>,
240 source: CrateId,
241 ) {
242 if !visited.insert(source) {
243 return;
244 }
245 for dep in graph[source].dependencies.iter() {
246 go(graph, visited, res, dep.crate_id)
247 }
248 res.push(source)
249 }
250 }
251
224 // FIXME: this only finds one crate with the given root; we could have multiple 252 // FIXME: this only finds one crate with the given root; we could have multiple
225 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 253 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
226 let (&crate_id, _) = 254 let (&crate_id, _) =
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 686cee3a1..aaf9b3b4b 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -77,6 +77,7 @@ pub use crate::{
77 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, 77 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
78 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, 78 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
79 markup::Markup, 79 markup::Markup,
80 prime_caches::PrimeCachesProgress,
80 references::{ 81 references::{
81 Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, RenameError, 82 Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, RenameError,
82 }, 83 },
@@ -223,8 +224,11 @@ impl Analysis {
223 self.with_db(|db| status::status(&*db, file_id)) 224 self.with_db(|db| status::status(&*db, file_id))
224 } 225 }
225 226
226 pub fn prime_caches(&self, files: Vec<FileId>) -> Cancelable<()> { 227 pub fn prime_caches<F>(&self, cb: F) -> Cancelable<()>
227 self.with_db(|db| prime_caches::prime_caches(db, files)) 228 where
229 F: Fn(PrimeCachesProgress) + Sync + std::panic::UnwindSafe,
230 {
231 self.with_db(move |db| prime_caches::prime_caches(db, &cb))
228 } 232 }
229 233
230 /// Gets the text of the source file. 234 /// Gets the text of the source file.
diff --git a/crates/ide/src/prime_caches.rs b/crates/ide/src/prime_caches.rs
index c5ab5a1d8..9687c2734 100644
--- a/crates/ide/src/prime_caches.rs
+++ b/crates/ide/src/prime_caches.rs
@@ -3,10 +3,45 @@
3//! request takes longer to compute. This modules implemented prepopulating of 3//! request takes longer to compute. This modules implemented prepopulating of
4//! various caches, it's not really advanced at the moment. 4//! various caches, it's not really advanced at the moment.
5 5
6use crate::{FileId, RootDatabase}; 6use base_db::SourceDatabase;
7use hir::db::DefDatabase;
7 8
8pub(crate) fn prime_caches(db: &RootDatabase, files: Vec<FileId>) { 9use crate::RootDatabase;
9 for file in files { 10
10 let _ = crate::syntax_highlighting::highlight(db, file, None, false); 11#[derive(Debug)]
12pub 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,
22}
23
24pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress) + Sync)) {
25 let _p = profile::span("prime_caches");
26 let graph = db.crate_graph();
27 let topo = &graph.crates_in_topological_order();
28
29 cb(PrimeCachesProgress::Started);
30
31 // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that.
32 // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks
33 // cancellation, so we cannot use rayon.
34 for (i, krate) in topo.iter().enumerate() {
35 let crate_name =
36 graph[*krate].declaration_name.as_ref().map(ToString::to_string).unwrap_or_default();
37
38 cb(PrimeCachesProgress::StartedOnCrate {
39 on_crate: crate_name,
40 n_done: i,
41 n_total: topo.len(),
42 });
43 db.crate_def_map(*krate);
11 } 44 }
45
46 cb(PrimeCachesProgress::Finished);
12} 47}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 06b38d99c..fb18f9014 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -7,6 +7,7 @@ use std::{
7 7
8use base_db::VfsPath; 8use base_db::VfsPath;
9use crossbeam_channel::{select, Receiver}; 9use crossbeam_channel::{select, Receiver};
10use ide::PrimeCachesProgress;
10use ide::{Canceled, FileId}; 11use ide::{Canceled, FileId};
11use lsp_server::{Connection, Notification, Request, Response}; 12use lsp_server::{Connection, Notification, Request, Response};
12use lsp_types::notification::Notification as _; 13use lsp_types::notification::Notification as _;
@@ -61,7 +62,7 @@ pub(crate) enum Task {
61 Response(Response), 62 Response(Response),
62 Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), 63 Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
63 Workspaces(Vec<anyhow::Result<ProjectWorkspace>>), 64 Workspaces(Vec<anyhow::Result<ProjectWorkspace>>),
64 Unit, 65 PrimeCaches(PrimeCachesProgress),
65} 66}
66 67
67impl fmt::Debug for Event { 68impl fmt::Debug for Event {
@@ -197,7 +198,28 @@ impl GlobalState {
197 } 198 }
198 } 199 }
199 Task::Workspaces(workspaces) => self.switch_workspaces(workspaces), 200 Task::Workspaces(workspaces) => self.switch_workspaces(workspaces),
200 Task::Unit => (), 201 Task::PrimeCaches(progress) => {
202 let (state, message, fraction);
203 match progress {
204 PrimeCachesProgress::Started => {
205 state = Progress::Begin;
206 message = None;
207 fraction = 0.0;
208 }
209 PrimeCachesProgress::StartedOnCrate { on_crate, n_done, n_total } => {
210 state = Progress::Report;
211 message = Some(format!("{}/{} ({})", n_done, n_total, on_crate));
212 fraction = Progress::fraction(n_done, n_total);
213 }
214 PrimeCachesProgress::Finished => {
215 state = Progress::End;
216 message = None;
217 fraction = 1.0;
218 }
219 };
220
221 self.report_progress("indexing", state, message, Some(fraction));
222 }
201 }, 223 },
202 Event::Vfs(mut task) => { 224 Event::Vfs(mut task) => {
203 let _p = profile::span("GlobalState::handle_event/vfs"); 225 let _p = profile::span("GlobalState::handle_event/vfs");
@@ -573,12 +595,18 @@ impl GlobalState {
573 Task::Diagnostics(diagnostics) 595 Task::Diagnostics(diagnostics)
574 }) 596 })
575 } 597 }
576 self.task_pool.handle.spawn({ 598 self.task_pool.handle.spawn_with_sender({
577 let subs = subscriptions;
578 let snap = self.snapshot(); 599 let snap = self.snapshot();
579 move || { 600 move |sender| {
580 snap.analysis.prime_caches(subs).unwrap_or_else(|_: Canceled| ()); 601 snap.analysis
581 Task::Unit 602 .prime_caches(|progress| {
603 sender.send(Task::PrimeCaches(progress)).unwrap();
604 })
605 .unwrap_or_else(|_: Canceled| {
606 // Pretend that we're done, so that the progress bar is removed. Otherwise
607 // the editor may complain about it already existing.
608 sender.send(Task::PrimeCaches(PrimeCachesProgress::Finished)).unwrap()
609 });
582 } 610 }
583 }); 611 });
584 } 612 }
diff --git a/crates/rust-analyzer/src/thread_pool.rs b/crates/rust-analyzer/src/thread_pool.rs
index 4fa502925..833893739 100644
--- a/crates/rust-analyzer/src/thread_pool.rs
+++ b/crates/rust-analyzer/src/thread_pool.rs
@@ -23,6 +23,17 @@ impl<T> TaskPool<T> {
23 }) 23 })
24 } 24 }
25 25
26 pub(crate) fn spawn_with_sender<F>(&mut self, task: F)
27 where
28 F: FnOnce(Sender<T>) + Send + 'static,
29 T: Send + 'static,
30 {
31 self.inner.execute({
32 let sender = self.sender.clone();
33 move || task(sender)
34 })
35 }
36
26 pub(crate) fn len(&self) -> usize { 37 pub(crate) fn len(&self) -> usize {
27 self.inner.queued_count() 38 self.inner.queued_count()
28 } 39 }