Skip to content

Commit d7aeed0

Browse files
authored
Merge pull request #21046 from Veykril/push-xluyprrqpzxz
perf: Improve start up time
2 parents afcfe14 + 309de02 commit d7aeed0

File tree

11 files changed

+198
-63
lines changed

11 files changed

+198
-63
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,11 @@ rayon = "1.10.0"
134134
rowan = "=0.15.15"
135135
# Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work
136136
# on impls without it
137-
salsa = { version = "0.24.0", default-features = true, features = [
137+
salsa = { version = "0.24.0", default-features = false, features = [
138138
"rayon",
139139
"salsa_unstable",
140140
"macros",
141+
"inventory",
141142
] }
142143
salsa-macros = "0.24.0"
143144
semver = "1.0.26"

crates/base-db/src/input.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,10 @@ impl Env {
867867
pub fn insert(&mut self, k: impl Into<String>, v: impl Into<String>) -> Option<String> {
868868
self.entries.insert(k.into(), v.into())
869869
}
870+
871+
pub fn contains_key(&self, arg: &str) -> bool {
872+
self.entries.contains_key(arg)
873+
}
870874
}
871875

872876
impl From<Env> for Vec<(String, String)> {

crates/hir/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ pub use {
136136
attr::{AttrSourceMap, Attrs, AttrsWithOwner},
137137
find_path::PrefixKind,
138138
import_map,
139-
lang_item::LangItem,
139+
lang_item::{LangItem, crate_lang_items},
140140
nameres::{DefMap, ModuleSource, crate_def_map},
141141
per_ns::Namespace,
142142
type_ref::{Mutability, TypeRef},

crates/ide-db/src/prime_caches.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,12 @@ pub fn parallel_prime_caches(
8383
crate_name,
8484
})?;
8585

86-
let cancelled = Cancelled::catch(|| _ = hir::crate_def_map(&db, crate_id));
86+
let cancelled = Cancelled::catch(|| {
87+
_ = hir::crate_def_map(&db, crate_id);
88+
// we compute the lang items here as the work for them is also highly recursive and will be trigger by the module symbols query
89+
// slowing down leaf crate analysis tremendously as we go back to being blocked on a single thread
90+
_ = hir::crate_lang_items(&db, crate_id);
91+
});
8792

8893
match cancelled {
8994
Ok(()) => progress_sender

crates/project-model/src/env.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
use base_db::Env;
33
use paths::Utf8Path;
44
use rustc_hash::FxHashMap;
5-
use toolchain::Tool;
65

76
use crate::{ManifestPath, PackageData, TargetKind, cargo_config_file::CargoConfigFile};
87

@@ -48,8 +47,8 @@ pub(crate) fn inject_cargo_package_env(env: &mut Env, package: &PackageData) {
4847
);
4948
}
5049

51-
pub(crate) fn inject_cargo_env(env: &mut Env) {
52-
env.set("CARGO", Tool::Cargo.path().to_string());
50+
pub(crate) fn inject_cargo_env(env: &mut Env, cargo_path: &Utf8Path) {
51+
env.set("CARGO", cargo_path.as_str());
5352
}
5453

5554
pub(crate) fn inject_rustc_tool_env(env: &mut Env, cargo_name: &str, kind: TargetKind) {

crates/project-model/src/sysroot.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use core::fmt;
88
use std::{env, fs, ops::Not, path::Path, process::Command};
99

1010
use anyhow::{Result, format_err};
11+
use base_db::Env;
1112
use itertools::Itertools;
1213
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
1314
use rustc_hash::FxHashMap;
@@ -172,6 +173,32 @@ impl Sysroot {
172173
}
173174
}
174175

176+
pub fn tool_path(&self, tool: Tool, current_dir: impl AsRef<Path>, envs: &Env) -> Utf8PathBuf {
177+
match self.root() {
178+
Some(root) => {
179+
let mut cmd = toolchain::command(
180+
Tool::Rustup.path(),
181+
current_dir,
182+
&envs
183+
.into_iter()
184+
.map(|(k, v)| (k.clone(), Some(v.clone())))
185+
.collect::<FxHashMap<_, _>>(),
186+
);
187+
if !envs.contains_key("RUSTUP_TOOLCHAIN")
188+
&& std::env::var_os("RUSTUP_TOOLCHAIN").is_none()
189+
{
190+
cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(root));
191+
}
192+
193+
cmd.arg("which");
194+
cmd.arg(tool.name());
195+
(|| Some(Utf8PathBuf::from(String::from_utf8(cmd.output().ok()?.stdout).ok()?)))()
196+
.unwrap_or_else(|| Utf8PathBuf::from(tool.name()))
197+
}
198+
_ => tool.path(),
199+
}
200+
}
201+
175202
pub fn discover_proc_macro_srv(&self) -> Option<anyhow::Result<AbsPathBuf>> {
176203
let root = self.root()?;
177204
Some(

crates/project-model/src/workspace.rs

Lines changed: 78 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! metadata` or `rust-project.json`) into representation stored in the salsa
33
//! database -- `CrateGraph`.
44
5+
use std::thread::Builder;
56
use std::{collections::VecDeque, fmt, fs, iter, ops::Deref, sync, thread};
67

78
use anyhow::Context;
@@ -12,7 +13,7 @@ use base_db::{
1213
};
1314
use cfg::{CfgAtom, CfgDiff, CfgOptions};
1415
use intern::{Symbol, sym};
15-
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
16+
use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
1617
use rustc_hash::{FxHashMap, FxHashSet};
1718
use semver::Version;
1819
use span::{Edition, FileId};
@@ -301,31 +302,39 @@ impl ProjectWorkspace {
301302
// We can speed up loading a bit by spawning all of these processes in parallel (especially
302303
// on systems were process spawning is delayed)
303304
let join = thread::scope(|s| {
304-
let rustc_cfg = s.spawn(|| {
305-
rustc_cfg::get(toolchain_config, targets.first().map(Deref::deref), extra_env)
306-
});
307-
let target_data = s.spawn(|| {
308-
target_data::get(
309-
toolchain_config,
310-
targets.first().map(Deref::deref),
311-
extra_env,
312-
).inspect_err(|e| {
313-
tracing::error!(%e, "failed fetching data layout for {cargo_toml:?} workspace")
305+
let rustc_cfg = Builder::new()
306+
.name("ProjectWorkspace::rustc_cfg".to_owned())
307+
.spawn_scoped(s, || {
308+
rustc_cfg::get(toolchain_config, targets.first().map(Deref::deref), extra_env)
314309
})
315-
});
316-
317-
let rustc_dir = s.spawn(|| {
318-
let rustc_dir = match rustc_source {
319-
Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone())
320-
.map_err(|p| Some(format!("rustc source path is not absolute: {p}"))),
321-
Some(RustLibSource::Discover) => {
322-
sysroot.discover_rustc_src().ok_or_else(|| {
323-
Some("Failed to discover rustc source for sysroot.".to_owned())
310+
.expect("failed to spawn thread");
311+
let target_data = Builder::new()
312+
.name("ProjectWorkspace::target_data".to_owned())
313+
.spawn_scoped(s, || {
314+
target_data::get(toolchain_config, targets.first().map(Deref::deref), extra_env)
315+
.inspect_err(|e| {
316+
tracing::error!(%e,
317+
"failed fetching data layout for \
318+
{cargo_toml:?} workspace"
319+
)
324320
})
325-
}
326-
None => Err(None),
327-
};
328-
rustc_dir.and_then(|rustc_dir| {
321+
})
322+
.expect("failed to spawn thread");
323+
324+
let rustc_dir = Builder::new()
325+
.name("ProjectWorkspace::rustc_dir".to_owned())
326+
.spawn_scoped(s, || {
327+
let rustc_dir = match rustc_source {
328+
Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone())
329+
.map_err(|p| Some(format!("rustc source path is not absolute: {p}"))),
330+
Some(RustLibSource::Discover) => {
331+
sysroot.discover_rustc_src().ok_or_else(|| {
332+
Some("Failed to discover rustc source for sysroot.".to_owned())
333+
})
334+
}
335+
None => Err(None),
336+
};
337+
rustc_dir.and_then(|rustc_dir| {
329338
info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
330339
match FetchMetadata::new(
331340
&rustc_dir,
@@ -359,31 +368,44 @@ impl ProjectWorkspace {
359368
Err(e) => {
360369
tracing::error!(
361370
%e,
362-
"Failed to read Cargo metadata from rustc source at {rustc_dir}",
371+
"Failed to read Cargo metadata from rustc source \
372+
at {rustc_dir}",
363373
);
364374
Err(Some(format!(
365-
"Failed to read Cargo metadata from rustc source at {rustc_dir}: {e}"
375+
"Failed to read Cargo metadata from rustc source \
376+
at {rustc_dir}: {e}"
366377
)))
367378
}
368379
}
369380
})
370-
});
371-
372-
let cargo_metadata = s.spawn(|| fetch_metadata.exec(false, progress));
373-
let loaded_sysroot = s.spawn(|| {
374-
sysroot.load_workspace(
375-
&RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
376-
config,
377-
workspace_dir,
378-
&targets,
379-
toolchain.clone(),
380-
)),
381-
config.no_deps,
382-
progress,
383-
)
384-
});
385-
let cargo_env =
386-
s.spawn(move || cargo_config_env(cargo_toml, &config_file, &config.extra_env));
381+
})
382+
.expect("failed to spawn thread");
383+
384+
let cargo_metadata = Builder::new()
385+
.name("ProjectWorkspace::cargo_metadata".to_owned())
386+
.spawn_scoped(s, || fetch_metadata.exec(false, progress))
387+
.expect("failed to spawn thread");
388+
let loaded_sysroot = Builder::new()
389+
.name("ProjectWorkspace::loaded_sysroot".to_owned())
390+
.spawn_scoped(s, || {
391+
sysroot.load_workspace(
392+
&RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
393+
config,
394+
workspace_dir,
395+
&targets,
396+
toolchain.clone(),
397+
)),
398+
config.no_deps,
399+
progress,
400+
)
401+
})
402+
.expect("failed to spawn thread");
403+
let cargo_env = Builder::new()
404+
.name("ProjectWorkspace::cargo_env".to_owned())
405+
.spawn_scoped(s, move || {
406+
cargo_config_env(cargo_toml, &config_file, &config.extra_env)
407+
})
408+
.expect("failed to spawn thread");
387409
thread::Result::Ok((
388410
rustc_cfg.join()?,
389411
target_data.join()?,
@@ -1194,6 +1216,7 @@ fn cargo_to_crate_graph(
11941216
load,
11951217
crate_ws_data.clone(),
11961218
);
1219+
let cargo_path = sysroot.tool_path(Tool::Cargo, cargo.workspace_root(), cargo.env());
11971220

11981221
let cfg_options = CfgOptions::from_iter(rustc_cfg);
11991222

@@ -1268,6 +1291,7 @@ fn cargo_to_crate_graph(
12681291
} else {
12691292
Arc::new(pkg_data.manifest.parent().to_path_buf())
12701293
},
1294+
&cargo_path,
12711295
);
12721296
if let TargetKind::Lib { .. } = kind {
12731297
lib_tgt = Some((crate_id, name.clone()));
@@ -1375,6 +1399,7 @@ fn cargo_to_crate_graph(
13751399
},
13761400
// FIXME: This looks incorrect but I don't think this causes problems.
13771401
crate_ws_data,
1402+
&cargo_path,
13781403
);
13791404
}
13801405
}
@@ -1453,6 +1478,7 @@ fn handle_rustc_crates(
14531478
override_cfg: &CfgOverrides,
14541479
build_scripts: &WorkspaceBuildScripts,
14551480
crate_ws_data: Arc<CrateWorkspaceData>,
1481+
cargo_path: &Utf8Path,
14561482
) {
14571483
let mut rustc_pkg_crates = FxHashMap::default();
14581484
// The root package of the rustc-dev component is rustc_driver, so we match that
@@ -1503,6 +1529,7 @@ fn handle_rustc_crates(
15031529
} else {
15041530
Arc::new(pkg_data.manifest.parent().to_path_buf())
15051531
},
1532+
cargo_path,
15061533
);
15071534
pkg_to_lib_crate.insert(pkg, crate_id);
15081535
// Add dependencies on core / std / alloc for this crate
@@ -1560,11 +1587,12 @@ fn add_target_crate_root(
15601587
build_data: Option<(&BuildScriptOutput, bool)>,
15611588
cfg_options: CfgOptions,
15621589
file_id: FileId,
1563-
cargo_name: &str,
1590+
cargo_crate_name: &str,
15641591
kind: TargetKind,
15651592
origin: CrateOrigin,
15661593
crate_ws_data: Arc<CrateWorkspaceData>,
15671594
proc_macro_cwd: Arc<AbsPathBuf>,
1595+
cargo_path: &Utf8Path,
15681596
) -> CrateBuilderId {
15691597
let edition = pkg.edition;
15701598
let potential_cfg_options = if pkg.features.is_empty() {
@@ -1591,16 +1619,16 @@ fn add_target_crate_root(
15911619

15921620
let mut env = cargo.env().clone();
15931621
inject_cargo_package_env(&mut env, pkg);
1594-
inject_cargo_env(&mut env);
1595-
inject_rustc_tool_env(&mut env, cargo_name, kind);
1622+
inject_cargo_env(&mut env, cargo_path);
1623+
inject_rustc_tool_env(&mut env, cargo_crate_name, kind);
15961624

15971625
if let Some(envs) = build_data.map(|(it, _)| &it.envs) {
15981626
env.extend_from_other(envs);
15991627
}
16001628
let crate_id = crate_graph.add_crate_root(
16011629
file_id,
16021630
edition,
1603-
Some(CrateDisplayName::from_canonical_name(cargo_name)),
1631+
Some(CrateDisplayName::from_canonical_name(cargo_crate_name)),
16041632
Some(pkg.version.to_string()),
16051633
cfg_options,
16061634
potential_cfg_options,
@@ -1614,7 +1642,9 @@ fn add_target_crate_root(
16141642
let proc_macro = match build_data {
16151643
Some((BuildScriptOutput { proc_macro_dylib_path, .. }, has_errors)) => {
16161644
match proc_macro_dylib_path {
1617-
ProcMacroDylibPath::Path(path) => Ok((cargo_name.to_owned(), path.clone())),
1645+
ProcMacroDylibPath::Path(path) => {
1646+
Ok((cargo_crate_name.to_owned(), path.clone()))
1647+
}
16181648
ProcMacroDylibPath::NotBuilt => Err(ProcMacroLoadingError::NotYetBuilt),
16191649
ProcMacroDylibPath::NotProcMacro | ProcMacroDylibPath::DylibNotFound
16201650
if has_errors =>

crates/rust-analyzer/src/bin/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,11 @@ fn run_server() -> anyhow::Result<()> {
307307
config.rediscover_workspaces();
308308
}
309309

310+
rayon::ThreadPoolBuilder::new()
311+
.thread_name(|ix| format!("RayonWorker{}", ix))
312+
.build_global()
313+
.unwrap();
314+
310315
// If the io_threads have an error, there's usually an error on the main
311316
// loop too because the channels are closed. Ensure we report both errors.
312317
match (rust_analyzer::main_loop(config, connection), io_threads.join()) {

crates/rust-analyzer/src/main_loop.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,11 @@ impl GlobalState {
452452
// Project has loaded properly, kick off initial flycheck
453453
self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None));
454454
}
455-
if self.config.prefill_caches() {
455+
// delay initial cache priming until proc macros are loaded, or we will load up a bunch of garbage into salsa
456+
let proc_macros_loaded = self.config.prefill_caches()
457+
&& !self.config.expand_proc_macros()
458+
|| self.fetch_proc_macros_queue.last_op_result().copied().unwrap_or(false);
459+
if proc_macros_loaded {
456460
self.prime_caches_queue.request_op("became quiescent".to_owned(), ());
457461
}
458462
}

0 commit comments

Comments
 (0)