Skip to content

Commit

Permalink
Avoid hashing the key twice in get_query().
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
nnethercote committed Nov 3, 2019
1 parent b497e18 commit 1aceaaa
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/librustc/lib.rs
Expand Up @@ -61,6 +61,7 @@
#![feature(log_syntax)]
#![feature(associated_type_bounds)]
#![feature(rustc_attrs)]
#![feature(hash_raw_entry)]

#![recursion_limit="512"]

Expand Down
16 changes: 13 additions & 3 deletions src/librustc/ty/query/plumbing.rs
Expand Up @@ -14,12 +14,13 @@ use errors::Level;
use errors::Diagnostic;
use errors::FatalError;
use errors::Handler;
use rustc_data_structures::fx::{FxHashMap};
use rustc_data_structures::fx::{FxHasher, FxHashMap};
use rustc_data_structures::sync::{Lrc, Lock};
use rustc_data_structures::sharded::Sharded;
use rustc_data_structures::thin_vec::ThinVec;
#[cfg(not(parallel_compiler))]
use rustc_data_structures::cold_path;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ptr;
use std::collections::hash_map::Entry;
Expand Down Expand Up @@ -80,8 +81,17 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
pub(super) fn try_get(tcx: TyCtxt<'tcx>, span: Span, key: &Q::Key) -> TryGetJob<'a, 'tcx, Q> {
let cache = Q::query_cache(tcx);
loop {
let mut lock = cache.get_shard_by_value(key).lock();
if let Some(value) = lock.results.get(key) {
// We compute the key's hash once and then use it for both the
// shard lookup and the hashmap lookup. This relies on the fact
// that both of them use `FxHasher`.
let mut state = FxHasher::default();
key.hash(&mut state);
let key_hash = state.finish();

let mut lock = cache.get_shard_by_hash(key_hash).lock();
if let Some((_, value)) =
lock.results.raw_entry().from_key_hashed_nocheck(key_hash, key)
{
tcx.prof.query_cache_hit(Q::NAME);
let result = (value.value.clone(), value.index);
#[cfg(debug_assertions)]
Expand Down
6 changes: 6 additions & 0 deletions src/librustc_data_structures/sharded.rs
Expand Up @@ -60,6 +60,7 @@ impl<T> Sharded<T> {
}
}

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

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

0 comments on commit 1aceaaa

Please sign in to comment.