From 11a7ff26457bc66deea3596c891de6cb23558bab Mon Sep 17 00:00:00 2001 From: shuo Date: Wed, 15 Feb 2023 04:19:26 +0000 Subject: [PATCH] =?UTF-8?q?use=20bevy=5Futils::HashMap=20for=20better=20pe?= =?UTF-8?q?rformance.=20TypeId=20is=20predefined=20=E2=80=A6=20(#7642)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …u64, so hash safety is not a concern # Objective - While reading the code, just noticed the BundleInfo's HashMap is std::collections::HashMap, which uses a slow but safe hasher. ## Solution - Use bevy_utils::HashMap instead benchmark diff (I run several times in a linux box, the perf improvement is consistent, though numbers varies from time to time, I paste my last run result here): ``` bash cargo bench -- spawn Compiling bevy_ecs v0.9.0 (/home/lishuo/developer/pr/bevy/crates/bevy_ecs) Compiling bevy_app v0.9.0 (/home/lishuo/developer/pr/bevy/crates/bevy_app) Compiling benches v0.1.0 (/home/lishuo/developer/pr/bevy/benches) Finished bench [optimized] target(s) in 1m 17s Running benches/bevy_ecs/change_detection.rs (/home/lishuo/developer/pr/bevy/benches/target/release/deps/change_detection-86c5445d0dc34529) Gnuplot not found, using plotters backend Running benches/bevy_ecs/benches.rs (/home/lishuo/developer/pr/bevy/benches/target/release/deps/ecs-e49b3abe80bfd8c0) Gnuplot not found, using plotters backend spawn_commands/2000_entities time: [153.94 µs 159.19 µs 164.37 µs] change: [-14.706% -11.050% -6.9633%] (p = 0.00 < 0.05) Performance has improved. spawn_commands/4000_entities time: [328.77 µs 339.11 µs 349.11 µs] change: [-7.6331% -3.9932% +0.0487%] (p = 0.06 > 0.05) No change in performance detected. spawn_commands/6000_entities time: [445.01 µs 461.29 µs 477.36 µs] change: [-16.639% -13.358% -10.006%] (p = 0.00 < 0.05) Performance has improved. spawn_commands/8000_entities time: [657.94 µs 677.71 µs 696.95 µs] change: [-8.8708% -5.2591% -1.6847%] (p = 0.01 < 0.05) Performance has improved. get_or_spawn/individual time: [452.02 µs 466.70 µs 482.07 µs] change: [-17.218% -14.041% -10.728%] (p = 0.00 < 0.05) Performance has improved. get_or_spawn/batched time: [291.12 µs 301.12 µs 311.31 µs] change: [-12.281% -8.9163% -5.3660%] (p = 0.00 < 0.05) Performance has improved. spawn_world/1_entities time: [81.668 ns 84.284 ns 86.860 ns] change: [-12.251% -6.7872% -1.5402%] (p = 0.02 < 0.05) Performance has improved. spawn_world/10_entities time: [789.78 ns 821.96 ns 851.95 ns] change: [-19.738% -14.186% -8.0733%] (p = 0.00 < 0.05) Performance has improved. spawn_world/100_entities time: [7.9906 µs 8.2449 µs 8.5013 µs] change: [-12.417% -6.6837% -0.8766%] (p = 0.02 < 0.05) Change within noise threshold. spawn_world/1000_entities time: [81.602 µs 84.161 µs 86.833 µs] change: [-13.656% -8.6520% -3.0491%] (p = 0.00 < 0.05) Performance has improved. Found 1 outliers among 100 measurements (1.00%) 1 (1.00%) high mild Benchmarking spawn_world/10000_entities: Warming up for 500.00 ms Warning: Unable to complete 100 samples in 4.0s. You may wish to increase target time to 4.0s, enable flat sampling, or reduce sample count to 70. spawn_world/10000_entities time: [813.02 µs 839.76 µs 865.41 µs] change: [-12.133% -6.1970% -0.2302%] (p = 0.05 < 0.05) Change within noise threshold. ``` --- ## Changelog > This section is optional. If this was a trivial fix, or has no externally-visible impact, you can delete this section. - use bevy_utils::HashMap for Bundles::bundle_ids ## Migration Guide > This section is optional. If there are no breaking changes, you can delete this section. - Not a breaking change, hashmap is internal impl. --- crates/bevy_ecs/Cargo.toml | 2 +- crates/bevy_ecs/src/archetype.rs | 3 +-- crates/bevy_ecs/src/bundle.rs | 5 +++-- crates/bevy_ecs/src/component.rs | 5 +++-- crates/bevy_ecs/src/lib.rs | 5 +++++ 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ecs/Cargo.toml b/crates/bevy_ecs/Cargo.toml index 15c8dd2bb3e51..4183b615a999c 100644 --- a/crates/bevy_ecs/Cargo.toml +++ b/crates/bevy_ecs/Cargo.toml @@ -24,7 +24,7 @@ async-channel = "1.4" event-listener = "2.5" thread_local = "1.1.4" fixedbitset = "0.4.2" -fxhash = "0.2" +rustc-hash = "1.1" downcast-rs = "1.2" serde = { version = "1", features = ["derive"] } diff --git a/crates/bevy_ecs/src/archetype.rs b/crates/bevy_ecs/src/archetype.rs index 777dd0d2e3fcd..bd2ceb5dcc582 100644 --- a/crates/bevy_ecs/src/archetype.rs +++ b/crates/bevy_ecs/src/archetype.rs @@ -26,7 +26,6 @@ use crate::{ storage::{ImmutableSparseSet, SparseArray, SparseSet, SparseSetIndex, TableId, TableRow}, }; use std::{ - collections::HashMap, hash::Hash, ops::{Index, IndexMut}, }; @@ -601,7 +600,7 @@ impl SparseSetIndex for ArchetypeComponentId { pub struct Archetypes { pub(crate) archetypes: Vec, pub(crate) archetype_component_count: usize, - archetype_ids: HashMap, + archetype_ids: bevy_utils::HashMap, } impl Archetypes { diff --git a/crates/bevy_ecs/src/bundle.rs b/crates/bevy_ecs/src/bundle.rs index 042138a3c0db8..34d9b428ca2c1 100644 --- a/crates/bevy_ecs/src/bundle.rs +++ b/crates/bevy_ecs/src/bundle.rs @@ -12,10 +12,11 @@ use crate::{ component::{Component, ComponentId, ComponentStorage, Components, StorageType, Tick}, entity::{Entities, Entity, EntityLocation}, storage::{SparseSetIndex, SparseSets, Storages, Table, TableRow}, + TypeIdMap, }; use bevy_ecs_macros::all_tuples; use bevy_ptr::OwningPtr; -use std::{any::TypeId, collections::HashMap}; +use std::any::TypeId; /// The `Bundle` trait enables insertion and removal of [`Component`]s from an entity. /// @@ -683,7 +684,7 @@ impl<'a, 'b> BundleSpawner<'a, 'b> { #[derive(Default)] pub struct Bundles { bundle_infos: Vec, - bundle_ids: HashMap, + bundle_ids: TypeIdMap, } impl Bundles { diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 745c75df6ff89..8d311686942b5 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -5,6 +5,7 @@ use crate::{ storage::{SparseSetIndex, Storages}, system::{Local, Resource}, world::{FromWorld, World}, + TypeIdMap, }; pub use bevy_ecs_macros::Component; use bevy_ptr::{OwningPtr, UnsafeCellDeref}; @@ -400,8 +401,8 @@ impl ComponentDescriptor { #[derive(Debug, Default)] pub struct Components { components: Vec, - indices: std::collections::HashMap, - resource_indices: std::collections::HashMap, + indices: TypeIdMap, + resource_indices: TypeIdMap, } impl Components { diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 77d6befc5d68d..38125d0b56dd5 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -19,6 +19,8 @@ pub mod storage; pub mod system; pub mod world; +use std::any::TypeId; + pub use bevy_ptr as ptr; /// Most commonly used re-exported types. @@ -52,6 +54,9 @@ pub mod prelude { pub use bevy_ecs_macros::all_tuples; +/// A specialized hashmap type with Key of `TypeId` +type TypeIdMap = rustc_hash::FxHashMap; + #[cfg(test)] mod tests { use crate as bevy_ecs;