Skip to content

Commit daf2204

Browse files
committed
Auto merge of rust-lang#91837 - Kobzol:stable-hash-map-avoid-sort, r=the8472
Avoid sorting in hash map stable hashing Suggested by `@the8472` [here](rust-lang#89404 (comment)). I hope that I understood it right, I replaced the sort with modular multiplication, which should be commutative. Can I ask for a perf. run? However, locally it didn't help at all. Creating the `StableHasher` all over again is probably slowing it down quite a lot. And using `FxHasher` is not straightforward, because the keys and values only implement `HashStable` (and probably they shouldn't be just hashed via `Hash` anyway for it to actually be stable). Maybe the `StableHash` interface could be changed somehow to better suppor these scenarios where the hasher is short-lived. Or the `StableHasher` implementation could have variants with e.g. a shorter buffer for these scenarios.
2 parents 91a0600 + 1f284b0 commit daf2204

File tree

1 file changed

+43
-23
lines changed

1 file changed

+43
-23
lines changed

compiler/rustc_data_structures/src/stable_hasher.rs

+43-23
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@ impl StableHasher {
4242
}
4343

4444
impl StableHasherResult for u128 {
45+
#[inline]
4546
fn finish(hasher: StableHasher) -> Self {
4647
let (_0, _1) = hasher.finalize();
4748
u128::from(_0) | (u128::from(_1) << 64)
4849
}
4950
}
5051

5152
impl StableHasherResult for u64 {
53+
#[inline]
5254
fn finish(hasher: StableHasher) -> Self {
5355
hasher.finalize().0
5456
}
@@ -507,7 +509,11 @@ where
507509
{
508510
#[inline]
509511
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
510-
hash_stable_hashmap(hcx, hasher, self, ToStableHashKey::to_stable_hash_key);
512+
stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, (key, value)| {
513+
let key = key.to_stable_hash_key(hcx);
514+
key.hash_stable(hcx, hasher);
515+
value.hash_stable(hcx, hasher);
516+
});
511517
}
512518
}
513519

@@ -517,9 +523,10 @@ where
517523
R: BuildHasher,
518524
{
519525
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
520-
let mut keys: Vec<_> = self.iter().map(|k| k.to_stable_hash_key(hcx)).collect();
521-
keys.sort_unstable();
522-
keys.hash_stable(hcx, hasher);
526+
stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, key| {
527+
let key = key.to_stable_hash_key(hcx);
528+
key.hash_stable(hcx, hasher);
529+
});
523530
}
524531
}
525532

@@ -529,10 +536,11 @@ where
529536
V: HashStable<HCX>,
530537
{
531538
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
532-
let mut entries: Vec<_> =
533-
self.iter().map(|(k, v)| (k.to_stable_hash_key(hcx), v)).collect();
534-
entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2));
535-
entries.hash_stable(hcx, hasher);
539+
stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, (key, value)| {
540+
let key = key.to_stable_hash_key(hcx);
541+
key.hash_stable(hcx, hasher);
542+
value.hash_stable(hcx, hasher);
543+
});
536544
}
537545
}
538546

@@ -541,26 +549,38 @@ where
541549
K: ToStableHashKey<HCX>,
542550
{
543551
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
544-
let mut keys: Vec<_> = self.iter().map(|k| k.to_stable_hash_key(hcx)).collect();
545-
keys.sort_unstable();
546-
keys.hash_stable(hcx, hasher);
552+
stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, key| {
553+
let key = key.to_stable_hash_key(hcx);
554+
key.hash_stable(hcx, hasher);
555+
});
547556
}
548557
}
549558

550-
pub fn hash_stable_hashmap<HCX, K, V, R, SK, F>(
559+
fn stable_hash_reduce<HCX, I, C, F>(
551560
hcx: &mut HCX,
552561
hasher: &mut StableHasher,
553-
map: &::std::collections::HashMap<K, V, R>,
554-
to_stable_hash_key: F,
562+
mut collection: C,
563+
length: usize,
564+
hash_function: F,
555565
) where
556-
K: Eq,
557-
V: HashStable<HCX>,
558-
R: BuildHasher,
559-
SK: HashStable<HCX> + Ord,
560-
F: Fn(&K, &HCX) -> SK,
566+
C: Iterator<Item = I>,
567+
F: Fn(&mut StableHasher, &mut HCX, I),
561568
{
562-
let mut entries: SmallVec<[_; 3]> =
563-
map.iter().map(|(k, v)| (to_stable_hash_key(k, hcx), v)).collect();
564-
entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2));
565-
entries.hash_stable(hcx, hasher);
569+
length.hash_stable(hcx, hasher);
570+
571+
match length {
572+
1 => {
573+
hash_function(hasher, hcx, collection.next().unwrap());
574+
}
575+
_ => {
576+
let hash = collection
577+
.map(|value| {
578+
let mut hasher = StableHasher::new();
579+
hash_function(&mut hasher, hcx, value);
580+
hasher.finish::<u128>()
581+
})
582+
.reduce(|accum, value| accum.wrapping_add(value));
583+
hash.hash_stable(hcx, hasher);
584+
}
585+
}
566586
}

0 commit comments

Comments
 (0)