Skip to content

Commit 1283c88

Browse files
authored
Rollup merge of rust-lang#66013 - nnethercote:avoid-hashing-twice-in-get_query, r=Zoxc
Avoid hashing the key twice in `get_query()`. For a single-threaded parallel compiler, this reduces instruction counts across several benchmarks, by up to 2.8%. The commit also adds documentation about `Sharded`'s use of `FxHasher`. r? @Zoxc
2 parents cb5a679 + 1aceaaa commit 1283c88

File tree

3 files changed

+20
-3
lines changed

3 files changed

+20
-3
lines changed

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#![feature(log_syntax)]
6060
#![feature(associated_type_bounds)]
6161
#![feature(rustc_attrs)]
62+
#![feature(hash_raw_entry)]
6263

6364
#![recursion_limit="512"]
6465

src/librustc/ty/query/plumbing.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ use errors::Level;
1414
use errors::Diagnostic;
1515
use errors::FatalError;
1616
use errors::Handler;
17-
use rustc_data_structures::fx::{FxHashMap};
17+
use rustc_data_structures::fx::{FxHasher, FxHashMap};
1818
use rustc_data_structures::sync::{Lrc, Lock};
1919
use rustc_data_structures::sharded::Sharded;
2020
use rustc_data_structures::thin_vec::ThinVec;
2121
#[cfg(not(parallel_compiler))]
2222
use rustc_data_structures::cold_path;
23+
use std::hash::{Hash, Hasher};
2324
use std::mem;
2425
use std::ptr;
2526
use std::collections::hash_map::Entry;
@@ -82,8 +83,17 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
8283
pub(super) fn try_get(tcx: TyCtxt<'tcx>, span: Span, key: &Q::Key) -> TryGetJob<'a, 'tcx, Q> {
8384
let cache = Q::query_cache(tcx);
8485
loop {
85-
let mut lock = cache.get_shard_by_value(key).lock();
86-
if let Some(value) = lock.results.get(key) {
86+
// We compute the key's hash once and then use it for both the
87+
// shard lookup and the hashmap lookup. This relies on the fact
88+
// that both of them use `FxHasher`.
89+
let mut state = FxHasher::default();
90+
key.hash(&mut state);
91+
let key_hash = state.finish();
92+
93+
let mut lock = cache.get_shard_by_hash(key_hash).lock();
94+
if let Some((_, value)) =
95+
lock.results.raw_entry().from_key_hashed_nocheck(key_hash, key)
96+
{
8797
tcx.prof.query_cache_hit(Q::NAME);
8898
let result = (value.value.clone(), value.index);
8999
#[cfg(debug_assertions)]

src/librustc_data_structures/sharded.rs

+6
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ impl<T> Sharded<T> {
6060
}
6161
}
6262

63+
/// The shard is selected by hashing `val` with `FxHasher`.
6364
#[inline]
6465
pub fn get_shard_by_value<K: Hash + ?Sized>(&self, val: &K) -> &Lock<T> {
6566
if SHARDS == 1 {
@@ -69,6 +70,11 @@ impl<T> Sharded<T> {
6970
}
7071
}
7172

73+
/// Get a shard with a pre-computed hash value. If `get_shard_by_value` is
74+
/// ever used in combination with `get_shard_by_hash` on a single `Sharded`
75+
/// instance, then `hash` must be computed with `FxHasher`. Otherwise,
76+
/// `hash` can be computed with any hasher, so long as that hasher is used
77+
/// consistently for each `Sharded` instance.
7278
#[inline]
7379
pub fn get_shard_by_hash(&self, hash: u64) -> &Lock<T> {
7480
let hash_len = mem::size_of::<usize>();

0 commit comments

Comments
 (0)