Skip to content

Commit b342c20

Browse files
authored
Merge pull request #21087 from Veykril/push-luroyzyzkwty
perf: Prime trait impls in cache priming
2 parents f9396bd + f1804ae commit b342c20

File tree

1 file changed

+104
-62
lines changed

1 file changed

+104
-62
lines changed

crates/ide-db/src/prime_caches.rs

Lines changed: 104 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub fn parallel_prime_caches(
3737
BeginCrateDefMap { crate_id: Crate, crate_name: Symbol },
3838
EndCrateDefMap { crate_id: Crate },
3939
EndCrateImportMap,
40+
EndSema,
4041
EndModuleSymbols,
4142
Cancelled(Cancelled),
4243
}
@@ -70,84 +71,113 @@ pub fn parallel_prime_caches(
7071
(reverse_deps, to_be_done_deps)
7172
};
7273

73-
let (def_map_work_sender, import_map_work_sender, symbols_work_sender, progress_receiver) = {
74+
let (
75+
def_map_work_sender,
76+
import_map_work_sender,
77+
symbols_work_sender,
78+
sema_work_sender,
79+
progress_receiver,
80+
) = {
7481
let (progress_sender, progress_receiver) = crossbeam_channel::unbounded();
7582
let (def_map_work_sender, def_map_work_receiver) = crossbeam_channel::unbounded();
7683
let (import_map_work_sender, import_map_work_receiver) = crossbeam_channel::unbounded();
84+
let (sema_work_sender, sema_work_receiver) = crossbeam_channel::unbounded();
7785
let (symbols_work_sender, symbols_work_receiver) = crossbeam_channel::unbounded();
78-
let prime_caches_worker =
79-
move |db: RootDatabase| {
80-
let handle_def_map = |crate_id, crate_name| {
81-
progress_sender.send(ParallelPrimeCacheWorkerProgress::BeginCrateDefMap {
82-
crate_id,
83-
crate_name,
84-
})?;
85-
86-
let cancelled = Cancelled::catch(|| {
87-
_ = hir::crate_def_map(&db, crate_id);
86+
let prime_caches_worker = move |db: RootDatabase| {
87+
let handle_def_map = |crate_id, crate_name| {
88+
progress_sender.send(ParallelPrimeCacheWorkerProgress::BeginCrateDefMap {
89+
crate_id,
90+
crate_name,
91+
})?;
92+
93+
let cancelled = Cancelled::catch(|| {
94+
_ = hir::crate_def_map(&db, crate_id);
95+
});
96+
97+
match cancelled {
98+
Ok(()) => progress_sender
99+
.send(ParallelPrimeCacheWorkerProgress::EndCrateDefMap { crate_id })?,
100+
Err(cancelled) => progress_sender
101+
.send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
102+
}
103+
104+
Ok::<_, crossbeam_channel::SendError<_>>(())
105+
};
106+
let handle_sema = |crate_id| {
107+
let cancelled = Cancelled::catch(|| {
108+
hir::attach_db(&db, || {
109+
// method resolution is likely to hit all trait impls at some point
110+
// we pre-populate it here as this will hit a lot of parses ...
111+
_ = hir::TraitImpls::for_crate(&db, crate_id);
88112
// we compute the lang items here as the work for them is also highly recursive and will be trigger by the module symbols query
89113
// slowing down leaf crate analysis tremendously as we go back to being blocked on a single thread
90114
_ = hir::crate_lang_items(&db, crate_id);
91-
});
92-
93-
match cancelled {
94-
Ok(()) => progress_sender
95-
.send(ParallelPrimeCacheWorkerProgress::EndCrateDefMap { crate_id })?,
96-
Err(cancelled) => progress_sender
97-
.send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
98-
}
115+
})
116+
});
99117

100-
Ok::<_, crossbeam_channel::SendError<_>>(())
101-
};
102-
let handle_import_map = |crate_id| {
103-
let cancelled = Cancelled::catch(|| _ = db.import_map(crate_id));
118+
match cancelled {
119+
Ok(()) => progress_sender.send(ParallelPrimeCacheWorkerProgress::EndSema)?,
120+
Err(cancelled) => progress_sender
121+
.send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
122+
}
104123

105-
match cancelled {
106-
Ok(()) => progress_sender
107-
.send(ParallelPrimeCacheWorkerProgress::EndCrateImportMap)?,
108-
Err(cancelled) => progress_sender
109-
.send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
110-
}
124+
Ok::<_, crossbeam_channel::SendError<_>>(())
125+
};
126+
let handle_import_map = |crate_id| {
127+
let cancelled = Cancelled::catch(|| _ = db.import_map(crate_id));
111128

112-
Ok::<_, crossbeam_channel::SendError<_>>(())
113-
};
114-
let handle_symbols = |module| {
115-
let cancelled = Cancelled::catch(AssertUnwindSafe(|| {
116-
_ = SymbolIndex::module_symbols(&db, module)
117-
}));
118-
119-
match cancelled {
120-
Ok(()) => progress_sender
121-
.send(ParallelPrimeCacheWorkerProgress::EndModuleSymbols)?,
122-
Err(cancelled) => progress_sender
123-
.send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
129+
match cancelled {
130+
Ok(()) => {
131+
progress_sender.send(ParallelPrimeCacheWorkerProgress::EndCrateImportMap)?
124132
}
133+
Err(cancelled) => progress_sender
134+
.send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
135+
}
125136

126-
Ok::<_, crossbeam_channel::SendError<_>>(())
127-
};
128-
129-
loop {
130-
db.unwind_if_revision_cancelled();
131-
132-
// Biased because we want to prefer def maps.
133-
crossbeam_channel::select_biased! {
134-
recv(def_map_work_receiver) -> work => {
135-
let Ok((crate_id, crate_name)) = work else { break };
136-
handle_def_map(crate_id, crate_name)?;
137-
}
138-
recv(import_map_work_receiver) -> work => {
139-
let Ok(crate_id) = work else { break };
140-
handle_import_map(crate_id)?;
141-
}
142-
recv(symbols_work_receiver) -> work => {
143-
let Ok(module) = work else { break };
144-
handle_symbols(module)?;
145-
}
137+
Ok::<_, crossbeam_channel::SendError<_>>(())
138+
};
139+
let handle_symbols = |module: hir::Module| {
140+
let cancelled = Cancelled::catch(AssertUnwindSafe(|| {
141+
_ = SymbolIndex::module_symbols(&db, module)
142+
}));
143+
144+
match cancelled {
145+
Ok(()) => {
146+
progress_sender.send(ParallelPrimeCacheWorkerProgress::EndModuleSymbols)?
146147
}
148+
Err(cancelled) => progress_sender
149+
.send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
147150
}
151+
148152
Ok::<_, crossbeam_channel::SendError<_>>(())
149153
};
150154

155+
loop {
156+
db.unwind_if_revision_cancelled();
157+
158+
// Biased because we want to prefer def maps.
159+
crossbeam_channel::select_biased! {
160+
recv(def_map_work_receiver) -> work => {
161+
let Ok((crate_id, crate_name)) = work else { break };
162+
handle_def_map(crate_id, crate_name)?;
163+
}
164+
recv(sema_work_receiver) -> work => {
165+
let Ok(crate_id) = work else { break };
166+
handle_sema(crate_id)?;
167+
}
168+
recv(import_map_work_receiver) -> work => {
169+
let Ok(crate_id) = work else { break };
170+
handle_import_map(crate_id)?;
171+
}
172+
recv(symbols_work_receiver) -> work => {
173+
let Ok(module) = work else { break };
174+
handle_symbols(module)?;
175+
}
176+
}
177+
}
178+
Ok::<_, crossbeam_channel::SendError<_>>(())
179+
};
180+
151181
for id in 0..num_worker_threads {
152182
stdx::thread::Builder::new(
153183
stdx::thread::ThreadIntent::Worker,
@@ -162,13 +192,20 @@ pub fn parallel_prime_caches(
162192
.expect("failed to spawn thread");
163193
}
164194

165-
(def_map_work_sender, import_map_work_sender, symbols_work_sender, progress_receiver)
195+
(
196+
def_map_work_sender,
197+
import_map_work_sender,
198+
symbols_work_sender,
199+
sema_work_sender,
200+
progress_receiver,
201+
)
166202
};
167203

168204
let crate_def_maps_total = db.all_crates().len();
169205
let mut crate_def_maps_done = 0;
170206
let (mut crate_import_maps_total, mut crate_import_maps_done) = (0usize, 0usize);
171207
let (mut module_symbols_total, mut module_symbols_done) = (0usize, 0usize);
208+
let (mut sema_total, mut sema_done) = (0usize, 0usize);
172209

173210
// an index map is used to preserve ordering so we can sort the progress report in order of
174211
// "longest crate to index" first
@@ -187,6 +224,7 @@ pub fn parallel_prime_caches(
187224
while crate_def_maps_done < crate_def_maps_total
188225
|| crate_import_maps_done < crate_import_maps_total
189226
|| module_symbols_done < module_symbols_total
227+
|| sema_done < sema_total
190228
{
191229
db.unwind_if_revision_cancelled();
192230

@@ -233,6 +271,7 @@ pub fn parallel_prime_caches(
233271
}
234272

235273
if crate_def_maps_done == crate_def_maps_total {
274+
// Can we trigger lru-eviction once at this point to reduce peak memory usage?
236275
cb(ParallelPrimeCachesProgress {
237276
crates_currently_indexing: vec![],
238277
crates_done: crate_def_maps_done,
@@ -241,6 +280,8 @@ pub fn parallel_prime_caches(
241280
});
242281
}
243282

283+
sema_work_sender.send(crate_id).ok();
284+
sema_total += 1;
244285
let origin = &crate_id.data(db).origin;
245286
if origin.is_lang() {
246287
crate_import_maps_total += 1;
@@ -264,6 +305,7 @@ pub fn parallel_prime_caches(
264305
}
265306
ParallelPrimeCacheWorkerProgress::EndCrateImportMap => crate_import_maps_done += 1,
266307
ParallelPrimeCacheWorkerProgress::EndModuleSymbols => module_symbols_done += 1,
308+
ParallelPrimeCacheWorkerProgress::EndSema => sema_done += 1,
267309
ParallelPrimeCacheWorkerProgress::Cancelled(cancelled) => {
268310
// Cancelled::throw should probably be public
269311
std::panic::resume_unwind(Box::new(cancelled));

0 commit comments

Comments
 (0)