Skip to content
/ rust Public
forked from rust-lang/rust

Commit fcd3349

Browse files
committed
Optimize hash map operations in the query system
1 parent 01dc45c commit fcd3349

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
]
@@ -3480,7 +3479,6 @@ dependencies = [
34803479
"either",
34813480
"elsa",
34823481
"ena",
3483-
"hashbrown 0.15.2",
34843482
"indexmap",
34853483
"jobserver",
34863484
"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::{outline, sync};
1615
use rustc_errors::{Diag, FatalError, StashKey};
@@ -25,8 +24,13 @@ use crate::query::caches::QueryCache;
2524
use crate::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryLatch, report_cycle};
2625
use crate::query::{QueryContext, QueryMap, QueryStackFrame, SerializedDepNodeIndex};
2726

27+
#[inline]
28+
fn equivalent_key<K: Eq, V>(k: &K) -> impl Fn(&(K, V)) -> bool + '_ {
29+
move |x| x.0 == *k
30+
}
31+
2832
pub struct QueryState<K> {
29-
active: Sharded<FxHashMap<K, QueryResult>>,
33+
active: Sharded<hashbrown::HashTable<(K, QueryResult)>>,
3034
}
3135

3236
/// Indicates the state of a query for a given key in a query map.
@@ -159,7 +163,7 @@ where
159163
{
160164
/// Completes the query by updating the query cache with the `result`,
161165
/// signals the waiter and forgets the JobOwner, so it won't poison the query
162-
fn complete<C>(self, cache: &C, result: C::Value, dep_node_index: DepNodeIndex)
166+
fn complete<C>(self, cache: &C, key_hash: u64, result: C::Value, dep_node_index: DepNodeIndex)
163167
where
164168
C: QueryCache<Key = K>,
165169
{
@@ -174,16 +178,17 @@ where
174178
cache.complete(key, result, dep_node_index);
175179

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

188193
job.signal_complete();
189194
}
@@ -199,11 +204,16 @@ where
199204
// Poison the query so jobs waiting on it panic.
200205
let state = self.state;
201206
let job = {
202-
let mut shard = state.active.lock_shard_by_value(&self.key);
203-
let job = shard.remove(&self.key).unwrap().expect_job();
204-
205-
shard.insert(self.key, QueryResult::Poisoned);
206-
job
207+
let key_hash = sharded::make_hash(&self.key);
208+
let mut shard = state.active.lock_shard_by_hash(key_hash);
209+
match shard.find_entry(key_hash, equivalent_key(&self.key)) {
210+
Err(_) => panic!(),
211+
Ok(occupied) => {
212+
let ((key, value), vacant) = occupied.remove();
213+
vacant.insert((key, QueryResult::Poisoned));
214+
value.expect_job()
215+
}
216+
}
207217
};
208218
// Also signal the completion of the job, so waiters
209219
// will continue execution.
@@ -283,11 +293,11 @@ where
283293
outline(|| {
284294
// We didn't find the query result in the query cache. Check if it was
285295
// poisoned due to a panic instead.
286-
let lock = query.query_state(qcx).active.get_shard_by_value(&key).lock();
287-
288-
match lock.get(&key) {
296+
let key_hash = sharded::make_hash(&key);
297+
let shard = query.query_state(qcx).active.lock_shard_by_hash(key_hash);
298+
match shard.find(key_hash, equivalent_key(&key)) {
289299
// The query we waited on panicked. Continue unwinding here.
290-
Some(QueryResult::Poisoned) => FatalError.raise(),
300+
Some((_, QueryResult::Poisoned)) => FatalError.raise(),
291301
_ => panic!(
292302
"query '{}' result must be in the cache or the query must be poisoned after a wait",
293303
query.name()
@@ -318,7 +328,8 @@ where
318328
Qcx: QueryContext,
319329
{
320330
let state = query.query_state(qcx);
321-
let mut state_lock = state.active.lock_shard_by_value(&key);
331+
let key_hash = sharded::make_hash(&key);
332+
let mut state_lock = state.active.lock_shard_by_hash(key_hash);
322333

323334
// For the parallel compiler we need to check both the query cache and query state structures
324335
// while holding the state lock to ensure that 1) the query has not yet completed and 2) the
@@ -335,21 +346,21 @@ where
335346

336347
let current_job_id = qcx.current_query_job();
337348

338-
match state_lock.entry(key) {
349+
match state_lock.entry(key_hash, equivalent_key(&key), |(k, _)| sharded::make_hash(k)) {
339350
Entry::Vacant(entry) => {
340351
// Nothing has computed or is computing the query, so we start a new job and insert it in the
341352
// state map.
342353
let id = qcx.next_job_id();
343354
let job = QueryJob::new(id, span, current_job_id);
344-
entry.insert(QueryResult::Started(job));
355+
entry.insert((key, QueryResult::Started(job)));
345356

346357
// Drop the lock before we start executing the query
347358
drop(state_lock);
348359

349-
execute_job::<_, _, INCR>(query, qcx, state, key, id, dep_node)
360+
execute_job::<_, _, INCR>(query, qcx, state, key, key_hash, id, dep_node)
350361
}
351362
Entry::Occupied(mut entry) => {
352-
match entry.get_mut() {
363+
match &mut entry.get_mut().1 {
353364
QueryResult::Started(job) => {
354365
if sync::is_dyn_thread_safe() {
355366
// Get the latch out
@@ -380,6 +391,7 @@ fn execute_job<Q, Qcx, const INCR: bool>(
380391
qcx: Qcx,
381392
state: &QueryState<Q::Key>,
382393
key: Q::Key,
394+
key_hash: u64,
383395
id: QueryJobId,
384396
dep_node: Option<DepNode>,
385397
) -> (Q::Value, Option<DepNodeIndex>)
@@ -440,7 +452,7 @@ where
440452
}
441453
}
442454
}
443-
job_owner.complete(cache, result, dep_node_index);
455+
job_owner.complete(cache, key_hash, result, dep_node_index);
444456

445457
(result, Some(dep_node_index))
446458
}

0 commit comments

Comments
 (0)