From 69760c78cff87f2a106ea6bbb5a810e994e453dc Mon Sep 17 00:00:00 2001 From: SpecificProtagonist Date: Sat, 13 Jan 2024 14:26:43 +0100 Subject: [PATCH] Skip rehashing TypeIds (#11268) # Objective `TypeId` contains a high-quality hash. Whenever a lookup based on a `TypeId` is performed (e.g. to insert/remove components), the hash is run through a second hash function. This is unnecessary. ## Solution Skip re-hashing `TypeId`s. In my [testing](https://gist.github.com/SpecificProtagonist/4b49ad74c6b82b0aedd3b4ea35121be8), this improves lookup performance consistently by 10%-15% (of course, the lookup is only a small part of e.g. a bundle insertion). --- crates/bevy_ecs/src/lib.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index ef0dd07a86..bd0a9f3463 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -54,7 +54,30 @@ pub mod prelude { pub use bevy_utils::all_tuples; /// A specialized hashmap type with Key of [`TypeId`] -type TypeIdMap = rustc_hash::FxHashMap; +type TypeIdMap = + std::collections::HashMap>; + +#[doc(hidden)] +#[derive(Default)] +struct NoOpTypeIdHasher(u64); + +// TypeId already contains a high-quality hash, so skip re-hashing that hash. +impl std::hash::Hasher for NoOpTypeIdHasher { + fn finish(&self) -> u64 { + self.0 + } + + fn write(&mut self, _bytes: &[u8]) { + // This will never be called: TypeId always just calls write_u64 once! + // This is unlikely to ever change, but as it isn't officially guaranteed, + // panicking will let us detect this as fast as possible. + unimplemented!("Hashing of std::any::TypeId changed"); + } + + fn write_u64(&mut self, i: u64) { + self.0 = i; + } +} #[cfg(test)] mod tests {