diff options
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 38 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 12 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/server_world.rs | 29 |
3 files changed, 67 insertions, 12 deletions
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index c3580ab67..e65bb0972 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -20,7 +20,7 @@ use crate::{ | |||
20 | main_loop::subscriptions::Subscriptions, | 20 | main_loop::subscriptions::Subscriptions, |
21 | project_model::workspace_loader, | 21 | project_model::workspace_loader, |
22 | req, | 22 | req, |
23 | server_world::{ServerWorld, ServerWorldState}, | 23 | server_world::{ServerWorld, ServerWorldState, CompletedRequest}, |
24 | Result, | 24 | Result, |
25 | InitializationOptions, | 25 | InitializationOptions, |
26 | }; | 26 | }; |
@@ -45,6 +45,17 @@ enum Task { | |||
45 | Notify(RawNotification), | 45 | Notify(RawNotification), |
46 | } | 46 | } |
47 | 47 | ||
48 | struct PendingRequest { | ||
49 | received: Instant, | ||
50 | method: String, | ||
51 | } | ||
52 | |||
53 | impl From<(u64, PendingRequest)> for CompletedRequest { | ||
54 | fn from((id, pending): (u64, PendingRequest)) -> CompletedRequest { | ||
55 | CompletedRequest { id, method: pending.method, duration: pending.received.elapsed() } | ||
56 | } | ||
57 | } | ||
58 | |||
48 | const THREADPOOL_SIZE: usize = 8; | 59 | const THREADPOOL_SIZE: usize = 8; |
49 | 60 | ||
50 | pub fn main_loop( | 61 | pub fn main_loop( |
@@ -97,7 +108,9 @@ pub fn main_loop( | |||
97 | ); | 108 | ); |
98 | 109 | ||
99 | log::info!("waiting for tasks to finish..."); | 110 | log::info!("waiting for tasks to finish..."); |
100 | task_receiver.into_iter().for_each(|task| on_task(task, msg_sender, &mut pending_requests)); | 111 | task_receiver |
112 | .into_iter() | ||
113 | .for_each(|task| on_task(task, msg_sender, &mut pending_requests, &mut state)); | ||
101 | log::info!("...tasks have finished"); | 114 | log::info!("...tasks have finished"); |
102 | log::info!("joining threadpool..."); | 115 | log::info!("joining threadpool..."); |
103 | drop(pool); | 116 | drop(pool); |
@@ -159,7 +172,7 @@ fn main_loop_inner( | |||
159 | task_sender: Sender<Task>, | 172 | task_sender: Sender<Task>, |
160 | task_receiver: Receiver<Task>, | 173 | task_receiver: Receiver<Task>, |
161 | state: &mut ServerWorldState, | 174 | state: &mut ServerWorldState, |
162 | pending_requests: &mut FxHashMap<u64, Instant>, | 175 | pending_requests: &mut FxHashMap<u64, PendingRequest>, |
163 | subs: &mut Subscriptions, | 176 | subs: &mut Subscriptions, |
164 | ) -> Result<()> { | 177 | ) -> Result<()> { |
165 | // We try not to index more than THREADPOOL_SIZE - 3 libraries at the same | 178 | // We try not to index more than THREADPOOL_SIZE - 3 libraries at the same |
@@ -195,7 +208,7 @@ fn main_loop_inner( | |||
195 | let mut state_changed = false; | 208 | let mut state_changed = false; |
196 | match event { | 209 | match event { |
197 | Event::Task(task) => { | 210 | Event::Task(task) => { |
198 | on_task(task, msg_sender, pending_requests); | 211 | on_task(task, msg_sender, pending_requests, state); |
199 | state.maybe_collect_garbage(); | 212 | state.maybe_collect_garbage(); |
200 | } | 213 | } |
201 | Event::Vfs(task) => { | 214 | Event::Vfs(task) => { |
@@ -292,12 +305,15 @@ fn main_loop_inner( | |||
292 | fn on_task( | 305 | fn on_task( |
293 | task: Task, | 306 | task: Task, |
294 | msg_sender: &Sender<RawMessage>, | 307 | msg_sender: &Sender<RawMessage>, |
295 | pending_requests: &mut FxHashMap<u64, Instant>, | 308 | pending_requests: &mut FxHashMap<u64, PendingRequest>, |
309 | state: &mut ServerWorldState, | ||
296 | ) { | 310 | ) { |
297 | match task { | 311 | match task { |
298 | Task::Respond(response) => { | 312 | Task::Respond(response) => { |
299 | if let Some(request_received) = pending_requests.remove(&response.id) { | 313 | if let Some(pending) = pending_requests.remove(&response.id) { |
300 | log::info!("handled req#{} in {:?}", response.id, request_received.elapsed()); | 314 | let completed = CompletedRequest::from((response.id, pending)); |
315 | log::info!("handled req#{} in {:?}", completed.id, completed.duration); | ||
316 | state.complete_request(completed); | ||
301 | msg_sender.send(response.into()).unwrap(); | 317 | msg_sender.send(response.into()).unwrap(); |
302 | } | 318 | } |
303 | } | 319 | } |
@@ -309,12 +325,13 @@ fn on_task( | |||
309 | 325 | ||
310 | fn on_request( | 326 | fn on_request( |
311 | world: &mut ServerWorldState, | 327 | world: &mut ServerWorldState, |
312 | pending_requests: &mut FxHashMap<u64, Instant>, | 328 | pending_requests: &mut FxHashMap<u64, PendingRequest>, |
313 | pool: &ThreadPool, | 329 | pool: &ThreadPool, |
314 | sender: &Sender<Task>, | 330 | sender: &Sender<Task>, |
315 | request_received: Instant, | 331 | request_received: Instant, |
316 | req: RawRequest, | 332 | req: RawRequest, |
317 | ) -> Result<Option<RawRequest>> { | 333 | ) -> Result<Option<RawRequest>> { |
334 | let method = req.method.clone(); | ||
318 | let mut pool_dispatcher = PoolDispatcher { req: Some(req), res: None, pool, world, sender }; | 335 | let mut pool_dispatcher = PoolDispatcher { req: Some(req), res: None, pool, world, sender }; |
319 | let req = pool_dispatcher | 336 | let req = pool_dispatcher |
320 | .on::<req::AnalyzerStatus>(handlers::handle_analyzer_status)? | 337 | .on::<req::AnalyzerStatus>(handlers::handle_analyzer_status)? |
@@ -348,7 +365,8 @@ fn on_request( | |||
348 | .finish(); | 365 | .finish(); |
349 | match req { | 366 | match req { |
350 | Ok(id) => { | 367 | Ok(id) => { |
351 | let prev = pending_requests.insert(id, request_received); | 368 | let prev = |
369 | pending_requests.insert(id, PendingRequest { method, received: request_received }); | ||
352 | assert!(prev.is_none(), "duplicate request: {}", id); | 370 | assert!(prev.is_none(), "duplicate request: {}", id); |
353 | Ok(None) | 371 | Ok(None) |
354 | } | 372 | } |
@@ -359,7 +377,7 @@ fn on_request( | |||
359 | fn on_notification( | 377 | fn on_notification( |
360 | msg_sender: &Sender<RawMessage>, | 378 | msg_sender: &Sender<RawMessage>, |
361 | state: &mut ServerWorldState, | 379 | state: &mut ServerWorldState, |
362 | pending_requests: &mut FxHashMap<u64, Instant>, | 380 | pending_requests: &mut FxHashMap<u64, PendingRequest>, |
363 | subs: &mut Subscriptions, | 381 | subs: &mut Subscriptions, |
364 | not: RawNotification, | 382 | not: RawNotification, |
365 | ) -> Result<()> { | 383 | ) -> Result<()> { |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index e36db12b3..dc817f2d9 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | use std::{io::Write as _, fmt::Write as _}; | ||
2 | |||
1 | use gen_lsp_server::ErrorCode; | 3 | use gen_lsp_server::ErrorCode; |
2 | use lsp_types::{ | 4 | use lsp_types::{ |
3 | CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity, CodeAction, | 5 | CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity, CodeAction, |
@@ -16,7 +18,6 @@ use ra_prof::profile; | |||
16 | use rustc_hash::FxHashMap; | 18 | use rustc_hash::FxHashMap; |
17 | use serde::{Serialize, Deserialize}; | 19 | use serde::{Serialize, Deserialize}; |
18 | use serde_json::to_value; | 20 | use serde_json::to_value; |
19 | use std::io::Write; | ||
20 | use url_serde::Ser; | 21 | use url_serde::Ser; |
21 | 22 | ||
22 | use crate::{ | 23 | use crate::{ |
@@ -28,7 +29,14 @@ use crate::{ | |||
28 | }; | 29 | }; |
29 | 30 | ||
30 | pub fn handle_analyzer_status(world: ServerWorld, _: ()) -> Result<String> { | 31 | pub fn handle_analyzer_status(world: ServerWorld, _: ()) -> Result<String> { |
31 | Ok(world.status()) | 32 | let mut buf = world.status(); |
33 | writeln!(buf, "\n\nrequests:").unwrap(); | ||
34 | let requests = world.latest_completed_requests.read(); | ||
35 | for (idx, r) in requests.iter().enumerate() { | ||
36 | let current = if idx == world.request_idx { "*" } else { " " }; | ||
37 | writeln!(buf, "{:4}{}{:<36}: {:?}", r.id, current, r.method, r.duration).unwrap(); | ||
38 | } | ||
39 | Ok(buf) | ||
32 | } | 40 | } |
33 | 41 | ||
34 | pub fn handle_syntax_tree(world: ServerWorld, params: req::SyntaxTreeParams) -> Result<String> { | 42 | pub fn handle_syntax_tree(world: ServerWorld, params: req::SyntaxTreeParams) -> Result<String> { |
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index b2808b817..b63927a4f 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | path::{Path, PathBuf}, | 2 | path::{Path, PathBuf}, |
3 | sync::Arc, | 3 | sync::Arc, |
4 | time::Duration, | ||
4 | }; | 5 | }; |
5 | 6 | ||
6 | use lsp_types::Url; | 7 | use lsp_types::Url; |
@@ -28,12 +29,26 @@ pub struct ServerWorldState { | |||
28 | pub workspaces: Arc<Vec<ProjectWorkspace>>, | 29 | pub workspaces: Arc<Vec<ProjectWorkspace>>, |
29 | pub analysis_host: AnalysisHost, | 30 | pub analysis_host: AnalysisHost, |
30 | pub vfs: Arc<RwLock<Vfs>>, | 31 | pub vfs: Arc<RwLock<Vfs>>, |
32 | // hand-rolling VecDeque here to print things in a nicer way | ||
33 | pub latest_completed_requests: Arc<RwLock<[CompletedRequest; N_COMPLETED_REQUESTS]>>, | ||
34 | pub request_idx: usize, | ||
31 | } | 35 | } |
32 | 36 | ||
37 | const N_COMPLETED_REQUESTS: usize = 10; | ||
38 | |||
33 | pub struct ServerWorld { | 39 | pub struct ServerWorld { |
34 | pub workspaces: Arc<Vec<ProjectWorkspace>>, | 40 | pub workspaces: Arc<Vec<ProjectWorkspace>>, |
35 | pub analysis: Analysis, | 41 | pub analysis: Analysis, |
36 | pub vfs: Arc<RwLock<Vfs>>, | 42 | pub vfs: Arc<RwLock<Vfs>>, |
43 | pub latest_completed_requests: Arc<RwLock<[CompletedRequest; N_COMPLETED_REQUESTS]>>, | ||
44 | pub request_idx: usize, | ||
45 | } | ||
46 | |||
47 | #[derive(Debug, Default)] | ||
48 | pub struct CompletedRequest { | ||
49 | pub id: u64, | ||
50 | pub method: String, | ||
51 | pub duration: Duration, | ||
37 | } | 52 | } |
38 | 53 | ||
39 | impl ServerWorldState { | 54 | impl ServerWorldState { |
@@ -73,6 +88,8 @@ impl ServerWorldState { | |||
73 | workspaces: Arc::new(workspaces), | 88 | workspaces: Arc::new(workspaces), |
74 | analysis_host, | 89 | analysis_host, |
75 | vfs: Arc::new(RwLock::new(vfs)), | 90 | vfs: Arc::new(RwLock::new(vfs)), |
91 | latest_completed_requests: Default::default(), | ||
92 | request_idx: 0, | ||
76 | } | 93 | } |
77 | } | 94 | } |
78 | 95 | ||
@@ -137,6 +154,8 @@ impl ServerWorldState { | |||
137 | workspaces: Arc::clone(&self.workspaces), | 154 | workspaces: Arc::clone(&self.workspaces), |
138 | analysis: self.analysis_host.analysis(), | 155 | analysis: self.analysis_host.analysis(), |
139 | vfs: Arc::clone(&self.vfs), | 156 | vfs: Arc::clone(&self.vfs), |
157 | latest_completed_requests: Arc::clone(&self.latest_completed_requests), | ||
158 | request_idx: self.request_idx.checked_sub(1).unwrap_or(N_COMPLETED_REQUESTS - 1), | ||
140 | } | 159 | } |
141 | } | 160 | } |
142 | 161 | ||
@@ -147,6 +166,16 @@ impl ServerWorldState { | |||
147 | pub fn collect_garbage(&mut self) { | 166 | pub fn collect_garbage(&mut self) { |
148 | self.analysis_host.collect_garbage() | 167 | self.analysis_host.collect_garbage() |
149 | } | 168 | } |
169 | |||
170 | pub fn complete_request(&mut self, request: CompletedRequest) { | ||
171 | // special case: don't track status request itself | ||
172 | if request.method == "rust-analyzer/analyzerStatus" { | ||
173 | return; | ||
174 | } | ||
175 | let idx = self.request_idx; | ||
176 | self.latest_completed_requests.write()[idx] = request; | ||
177 | self.request_idx = (idx + 1) % N_COMPLETED_REQUESTS; | ||
178 | } | ||
150 | } | 179 | } |
151 | 180 | ||
152 | impl ServerWorld { | 181 | impl ServerWorld { |