Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ebaedae

Browse files
committedMar 13, 2025
Optimize hash map operations in the query system
1 parent 961351c commit ebaedae

File tree

6 files changed

+46
-37
lines changed

6 files changed

+46
-37
lines changed
 

‎Cargo.lock

-2
Original file line numberDiff line numberDiff line change
@@ -1491,7 +1491,6 @@ version = "0.15.2"
14911491
source = "registry+https://github.com/rust-lang/crates.io-index"
14921492
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
14931493
dependencies = [
1494-
"allocator-api2",
14951494
"foldhash",
14961495
"serde",
14971496
]
@@ -3493,7 +3492,6 @@ dependencies = [
34933492
"either",
34943493
"elsa",
34953494
"ena",
3496-
"hashbrown 0.15.2",
34973495
"indexmap",
34983496
"jobserver",
34993497
"libc",

‎compiler/rustc_data_structures/Cargo.toml

-5
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,6 @@ thin-vec = "0.2.12"
2929
tracing = "0.1"
3030
# tidy-alphabetical-end
3131

32-
[dependencies.hashbrown]
33-
version = "0.15.2"
34-
default-features = false
35-
features = ["nightly"] # for may_dangle
36-
3732
[dependencies.parking_lot]
3833
version = "0.12"
3934

‎compiler/rustc_data_structures/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#![feature(unwrap_infallible)]
3939
// tidy-alphabetical-end
4040

41+
extern crate hashbrown;
42+
4143
use std::fmt;
4244

4345
pub use atomic_ref::AtomicRef;

‎compiler/rustc_data_structures/src/sharded.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ impl<K: Eq + Hash + Copy + IntoPointer> ShardedHashMap<K, ()> {
256256
}
257257

258258
#[inline]
259-
fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
259+
pub fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
260260
let mut state = FxHasher::default();
261261
val.hash(&mut state);
262262
state.finish()

‎compiler/rustc_query_system/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#![feature(min_specialization)]
88
// tidy-alphabetical-end
99

10+
extern crate hashbrown;
11+
1012
pub mod cache;
1113
pub mod dep_graph;
1214
mod error;

‎compiler/rustc_query_system/src/query/plumbing.rs

+41-29
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
//! manage the caches, and so forth.
44
55
use std::cell::Cell;
6-
use std::collections::hash_map::Entry;
76
use std::fmt::Debug;
87
use std::hash::Hash;
98
use std::mem;
109

10+
use hashbrown::hash_table::Entry;
1111
use rustc_data_structures::fingerprint::Fingerprint;
12-
use rustc_data_structures::fx::FxHashMap;
13-
use rustc_data_structures::sharded::Sharded;
12+
use rustc_data_structures::sharded::{self, Sharded};
1413
use rustc_data_structures::stack::ensure_sufficient_stack;
1514
use rustc_data_structures::sync::Lock;
1615
use rustc_data_structures::{outline, sync};
@@ -29,8 +28,13 @@ use crate::query::{
2928
QueryContext, QueryMap, QuerySideEffects, QueryStackFrame, SerializedDepNodeIndex,
3029
};
3130

31+
#[inline]
32+
fn equivalent_key<K: Eq, V>(k: &K) -> impl Fn(&(K, V)) -> bool + '_ {
33+
move |x| x.0 == *k
34+
}
35+
3236
pub struct QueryState<K> {
33-
active: Sharded<FxHashMap<K, QueryResult>>,
37+
active: Sharded<hashbrown::HashTable<(K, QueryResult)>>,
3438
}
3539

3640
/// Indicates the state of a query for a given key in a query map.
@@ -163,7 +167,7 @@ where
163167
{
164168
/// Completes the query by updating the query cache with the `result`,
165169
/// signals the waiter and forgets the JobOwner, so it won't poison the query
166-
fn complete<C>(self, cache: &C, result: C::Value, dep_node_index: DepNodeIndex)
170+
fn complete<C>(self, cache: &C, key_hash: u64, result: C::Value, dep_node_index: DepNodeIndex)
167171
where
168172
C: QueryCache<Key = K>,
169173
{
@@ -178,16 +182,17 @@ where
178182
cache.complete(key, result, dep_node_index);
179183

180184
let job = {
181-
let val = {
182-
// don't keep the lock during the `unwrap()` of the retrieved value, or we taint the
183-
// underlying shard.
184-
// since unwinding also wants to look at this map, this can also prevent a double
185-
// panic.
186-
let mut lock = state.active.lock_shard_by_value(&key);
187-
lock.remove(&key)
188-
};
189-
val.unwrap().expect_job()
185+
// don't keep the lock during the `unwrap()` of the retrieved value, or we taint the
186+
// underlying shard.
187+
// since unwinding also wants to look at this map, this can also prevent a double
188+
// panic.
189+
let mut shard = state.active.lock_shard_by_hash(key_hash);
190+
match shard.find_entry(key_hash, equivalent_key(&key)) {
191+
Err(_) => None,
192+
Ok(occupied) => Some(occupied.remove().0.1),
193+
}
190194
};
195+
let job = job.expect("active query job entry").expect_job();
191196

192197
job.signal_complete();
193198
}
@@ -203,11 +208,16 @@ where
203208
// Poison the query so jobs waiting on it panic.
204209
let state = self.state;
205210
let job = {
206-
let mut shard = state.active.lock_shard_by_value(&self.key);
207-
let job = shard.remove(&self.key).unwrap().expect_job();
208-
209-
shard.insert(self.key, QueryResult::Poisoned);
210-
job
211+
let key_hash = sharded::make_hash(&self.key);
212+
let mut shard = state.active.lock_shard_by_hash(key_hash);
213+
match shard.find_entry(key_hash, equivalent_key(&self.key)) {
214+
Err(_) => panic!(),
215+
Ok(occupied) => {
216+
let ((key, value), vacant) = occupied.remove();
217+
vacant.insert((key, QueryResult::Poisoned));
218+
value.expect_job()
219+
}
220+
}
211221
};
212222
// Also signal the completion of the job, so waiters
213223
// will continue execution.
@@ -287,11 +297,11 @@ where
287297
outline(|| {
288298
// We didn't find the query result in the query cache. Check if it was
289299
// poisoned due to a panic instead.
290-
let lock = query.query_state(qcx).active.get_shard_by_value(&key).lock();
291-
292-
match lock.get(&key) {
300+
let key_hash = sharded::make_hash(&key);
301+
let shard = query.query_state(qcx).active.lock_shard_by_hash(key_hash);
302+
match shard.find(key_hash, equivalent_key(&key)) {
293303
// The query we waited on panicked. Continue unwinding here.
294-
Some(QueryResult::Poisoned) => FatalError.raise(),
304+
Some((_, QueryResult::Poisoned)) => FatalError.raise(),
295305
_ => panic!(
296306
"query '{}' result must be in the cache or the query must be poisoned after a wait",
297307
query.name()
@@ -322,7 +332,8 @@ where
322332
Qcx: QueryContext,
323333
{
324334
let state = query.query_state(qcx);
325-
let mut state_lock = state.active.lock_shard_by_value(&key);
335+
let key_hash = sharded::make_hash(&key);
336+
let mut state_lock = state.active.lock_shard_by_hash(key_hash);
326337

327338
// For the parallel compiler we need to check both the query cache and query state structures
328339
// while holding the state lock to ensure that 1) the query has not yet completed and 2) the
@@ -339,21 +350,21 @@ where
339350

340351
let current_job_id = qcx.current_query_job();
341352

342-
match state_lock.entry(key) {
353+
match state_lock.entry(key_hash, equivalent_key(&key), |(k, _)| sharded::make_hash(k)) {
343354
Entry::Vacant(entry) => {
344355
// Nothing has computed or is computing the query, so we start a new job and insert it in the
345356
// state map.
346357
let id = qcx.next_job_id();
347358
let job = QueryJob::new(id, span, current_job_id);
348-
entry.insert(QueryResult::Started(job));
359+
entry.insert((key, QueryResult::Started(job)));
349360

350361
// Drop the lock before we start executing the query
351362
drop(state_lock);
352363

353-
execute_job::<_, _, INCR>(query, qcx, state, key, id, dep_node)
364+
execute_job::<_, _, INCR>(query, qcx, state, key, key_hash, id, dep_node)
354365
}
355366
Entry::Occupied(mut entry) => {
356-
match entry.get_mut() {
367+
match &mut entry.get_mut().1 {
357368
QueryResult::Started(job) => {
358369
if sync::is_dyn_thread_safe() {
359370
// Get the latch out
@@ -384,6 +395,7 @@ fn execute_job<Q, Qcx, const INCR: bool>(
384395
qcx: Qcx,
385396
state: &QueryState<Q::Key>,
386397
key: Q::Key,
398+
key_hash: u64,
387399
id: QueryJobId,
388400
dep_node: Option<DepNode>,
389401
) -> (Q::Value, Option<DepNodeIndex>)
@@ -444,7 +456,7 @@ where
444456
}
445457
}
446458
}
447-
job_owner.complete(cache, result, dep_node_index);
459+
job_owner.complete(cache, key_hash, result, dep_node_index);
448460

449461
(result, Some(dep_node_index))
450462
}

0 commit comments

Comments
 (0)
Failed to load comments.