diff --git a/Cargo.lock b/Cargo.lock index 07fff9af5d..8e320458bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1079,6 +1079,7 @@ dependencies = [ "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "test_utils 0.1.0", "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/bors.toml b/bors.toml index bf5553df46..0bc71860f2 100644 --- a/bors.toml +++ b/bors.toml @@ -1,6 +1,6 @@ status = [ "Rust (ubuntu-latest)", - # "Rust (windows-latest)", + "Rust (windows-latest)", "Rust (macos-latest)", "TypeScript" ] diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index 5df0496dd7..fdf81ed87c 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml @@ -30,6 +30,9 @@ env_logger = { version = "0.7.1", default-features = false } ra_cargo_watch = { path = "../ra_cargo_watch" } either = "1.5" +[target.'cfg(windows)'.dependencies] +winapi = "0.3" + [dev-dependencies] tempfile = "3" test_utils = { path = "../test_utils" } diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 83adf9711f..15bf519c9a 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -29,9 +29,6 @@ use crate::{ Result, ServerConfig, }; -const THREADPOOL_SIZE: usize = 8; -const MAX_IN_FLIGHT_LIBS: usize = THREADPOOL_SIZE - 3; - #[derive(Debug)] pub struct LspError { pub code: i32, @@ -60,6 +57,25 @@ pub fn main_loop( ) -> Result<()> { log::info!("server_config: {:#?}", config); + // Windows scheduler implements priority boosts: if thread waits for an + // event (like a condvar), and event fires, priority of the thread is + // temporary bumped. This optimization backfires in our case: each time the + // `main_loop` schedules a task to run on a threadpool, the worker threads + // gets a higher priority, and (on a machine with fewer cores) displaces the + // main loop! We work-around this by marking the main loop as a + // higher-priority thread. + // + // https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities + // https://docs.microsoft.com/en-us/windows/win32/procthread/priority-boosts + // https://github.com/rust-analyzer/rust-analyzer/issues/2835 + #[cfg(windows)] + unsafe { + use winapi::um::processthreadsapi::*; + let thread = GetCurrentThread(); + let thread_priority_above_normal = 1; + SetThreadPriority(thread, thread_priority_above_normal); + } + let mut loop_state = LoopState::default(); let mut world_state = { let feature_flags = { @@ -168,7 +184,7 @@ pub fn main_loop( ) }; - let pool = ThreadPool::new(THREADPOOL_SIZE); + let pool = ThreadPool::default(); let (task_sender, task_receiver) = unbounded::(); let (libdata_sender, libdata_receiver) = unbounded::(); @@ -371,7 +387,8 @@ fn loop_turn( loop_state.pending_libraries.extend(changes); } - while loop_state.in_flight_libraries < MAX_IN_FLIGHT_LIBS + let max_in_flight_libs = pool.max_count().saturating_sub(2).max(1); + while loop_state.in_flight_libraries < max_in_flight_libs && !loop_state.pending_libraries.is_empty() { let (root, files) = loop_state.pending_libraries.pop().unwrap();