Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #13744 - vtta:numthreads, r=Veykril
feat: add the ability to limit the number of threads launched by `main_loop` ## Motivation `main_loop` defaults to launch as many threads as cpus in one machine. When developing on multi-core remote servers on multiple projects, this will lead to thousands of idle threads being created. This is very annoying when one wants check whether his program under developing is running correctly via `htop`. <img width="756" alt="image" src="https://user-images.githubusercontent.com/41831480/206656419-fa3f0dd2-e554-4f36-be1b-29d54739930c.png"> ## Contribution This patch introduce the configuration option `rust-analyzer.numThreads` to set the desired thread number used by the main thread pool. This should have no effects on the performance as not all threads are actually used. <img width="1325" alt="image" src="https://user-images.githubusercontent.com/41831480/206656834-fe625c4c-b993-4771-8a82-7427c297fd41.png"> ## Demonstration The following is a snippet of `lunarvim` configuration using my own build. ```lua vim.list_extend(lvim.lsp.automatic_configuration.skipped_servers, { "rust_analyzer" }) require("lvim.lsp.manager").setup("rust_analyzer", { cmd = { "env", "RA_LOG=debug", "RA_LOG_FILE=/tmp/ra-test.log", "/home/jlhu/Projects/rust-analyzer/target/debug/rust-analyzer", }, init_options = { numThreads = 4, }, settings = { cachePriming = { numThreads = 8, }, }, }) ``` ## Limitations The `numThreads` can only be modified via `initializationOptions` in early initialisation because everything has to wait until the thread pool starts including the dynamic settings modification support. The `numThreads` also does not reflect the end results of how many threads is actually created, because I have not yet tracked down everything that spawns threads.
bors 2023-01-09
parent 1e20bf3 · parent 9f5a547 · commit fe8ee9c
-rw-r--r--crates/rust-analyzer/src/config.rs7
-rw-r--r--crates/rust-analyzer/src/global_state.rs2
-rw-r--r--crates/rust-analyzer/src/task_pool.rs3
-rw-r--r--docs/user/generated_config.adoc5
-rw-r--r--editors/code/package.json9
5 files changed, 24 insertions, 2 deletions
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 4ee92b3d4e..0f515a6d5c 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -409,6 +409,9 @@ config_data! {
/// Whether to show `can't find Cargo.toml` error message.
notifications_cargoTomlNotFound: bool = "true",
+ /// How many worker threads in the main loop. The default `null` means to pick automatically.
+ numThreads: Option<usize> = "null",
+
/// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.
procMacro_attributes_enable: bool = "true",
/// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.
@@ -1482,6 +1485,10 @@ impl Config {
}
}
+ pub fn main_loop_num_threads(&self) -> usize {
+ self.data.numThreads.unwrap_or(num_cpus::get_physical().try_into().unwrap_or(1))
+ }
+
pub fn typing_autoclose_angle(&self) -> bool {
self.data.typing_autoClosingAngleBrackets_enable
}
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 7f6ced26ce..c6f4e9ce07 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -134,7 +134,7 @@ impl GlobalState {
let task_pool = {
let (sender, receiver) = unbounded();
- let handle = TaskPool::new(sender);
+ let handle = TaskPool::new_with_threads(sender, config.main_loop_num_threads());
Handle { handle, receiver }
};
diff --git a/crates/rust-analyzer/src/task_pool.rs b/crates/rust-analyzer/src/task_pool.rs
index aeeb3b7c58..616e449984 100644
--- a/crates/rust-analyzer/src/task_pool.rs
+++ b/crates/rust-analyzer/src/task_pool.rs
@@ -8,12 +8,13 @@ pub(crate) struct TaskPool<T> {
}
impl<T> TaskPool<T> {
- pub(crate) fn new(sender: Sender<T>) -> TaskPool<T> {
+ pub(crate) fn new_with_threads(sender: Sender<T>, threads: usize) -> TaskPool<T> {
const STACK_SIZE: usize = 8 * 1024 * 1024;
let inner = threadpool::Builder::new()
.thread_name("Worker".into())
.thread_stack_size(STACK_SIZE)
+ .num_threads(threads)
.build();
TaskPool { sender, inner }
}
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 91f8e98449..d9794e7052 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -619,6 +619,11 @@ Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
--
Whether to show `can't find Cargo.toml` error message.
--
+[[rust-analyzer.numThreads]]rust-analyzer.numThreads (default: `null`)::
++
+--
+How many worker threads in the main loop. The default `null` means to pick automatically.
+--
[[rust-analyzer.procMacro.attributes.enable]]rust-analyzer.procMacro.attributes.enable (default: `true`)::
+
--
diff --git a/editors/code/package.json b/editors/code/package.json
index 454b95a63b..f508dde4f6 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -1177,6 +1177,15 @@
"default": true,
"type": "boolean"
},
+ "rust-analyzer.numThreads": {
+ "markdownDescription": "How many worker threads in the main loop. The default `null` means to pick automatically.",
+ "default": null,
+ "type": [
+ "null",
+ "integer"
+ ],
+ "minimum": 0
+ },
"rust-analyzer.procMacro.attributes.enable": {
"markdownDescription": "Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.",
"default": true,