Skip to content

Commit fbf08ac

Browse files
authored
Faster compilation of bevy_diagnostic (#1235)
* Remove AHashExt There is little benefit of Hash*::new() over Hash*::default(), but it does require more code that needs to be duplicated for every Hash* in bevy_utils. It may also slightly increase compile times. * Add StableHash* to bevy_utils * Use StableHashMap instead of HashMap + BTreeSet for diagnostics This is a significant reduction in the release mode compile times of bevy_diagnostics ``` Benchmark #1: touch crates/bevy_diagnostic/src/lib.rs && cargo build --release -p bevy_diagnostic -j1 Time (mean ± σ): 3.645 s ± 0.009 s [User: 3.551 s, System: 0.094 s] Range (min … max): 3.632 s … 3.658 s 20 runs ``` ``` Benchmark #1: touch crates/bevy_diagnostic/src/lib.rs && cargo build --release -p bevy_diagnostic -j1 Time (mean ± σ): 2.938 s ± 0.012 s [User: 2.850 s, System: 0.090 s] Range (min … max): 2.919 s … 2.969 s 20 runs ```
1 parent c434f57 commit fbf08ac

File tree

6 files changed

+42
-92
lines changed

6 files changed

+42
-92
lines changed

crates/bevy_diagnostic/src/diagnostic.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use bevy_utils::{Duration, HashMap, Instant, Uuid};
2-
use std::collections::{BTreeSet, VecDeque};
1+
use bevy_utils::{Duration, Instant, StableHashMap, Uuid};
2+
use std::collections::VecDeque;
33

44
/// Unique identifier for a [Diagnostic]
55
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
@@ -101,13 +101,13 @@ impl Diagnostic {
101101
/// A collection of [Diagnostic]s
102102
#[derive(Debug, Default)]
103103
pub struct Diagnostics {
104-
diagnostics: HashMap<DiagnosticId, Diagnostic>,
105-
ordered_diagnostics: BTreeSet<DiagnosticId>,
104+
// This uses a [`StableHashMap`] to ensure that the iteration order is deterministic between
105+
// runs when all diagnostics are inserted in the same order.
106+
diagnostics: StableHashMap<DiagnosticId, Diagnostic>,
106107
}
107108

108109
impl Diagnostics {
109110
pub fn add(&mut self, diagnostic: Diagnostic) {
110-
self.ordered_diagnostics.insert(diagnostic.id);
111111
self.diagnostics.insert(diagnostic.id, diagnostic);
112112
}
113113

@@ -134,10 +134,4 @@ impl Diagnostics {
134134
pub fn iter(&self) -> impl Iterator<Item = &Diagnostic> {
135135
self.diagnostics.values()
136136
}
137-
138-
pub fn ordered_iter(&self) -> impl Iterator<Item = &Diagnostic> {
139-
self.ordered_diagnostics
140-
.iter()
141-
.filter_map(move |k| self.diagnostics.get(k))
142-
}
143137
}

crates/bevy_diagnostic/src/log_diagnostics_plugin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl LogDiagnosticsPlugin {
7878
Self::log_diagnostic(diagnostic);
7979
}
8080
} else {
81-
for diagnostic in diagnostics.ordered_iter() {
81+
for diagnostic in diagnostics.iter() {
8282
Self::log_diagnostic(diagnostic);
8383
}
8484
}
@@ -96,7 +96,7 @@ impl LogDiagnosticsPlugin {
9696
debug!("{:#?}\n", diagnostic);
9797
}
9898
} else {
99-
for diagnostic in diagnostics.ordered_iter() {
99+
for diagnostic in diagnostics.iter() {
100100
debug!("{:#?}\n", diagnostic);
101101
}
102102
}

crates/bevy_input/src/axis.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use bevy_utils::{AHashExt, HashMap};
1+
use bevy_utils::HashMap;
22
use std::hash::Hash;
33

44
#[derive(Debug)]
@@ -12,7 +12,7 @@ where
1212
{
1313
fn default() -> Self {
1414
Axis {
15-
axis_data: HashMap::new(),
15+
axis_data: HashMap::default(),
1616
}
1717
}
1818
}

crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
use bevy_app::prelude::{EventReader, Events};
77
use bevy_asset::{AssetEvent, Assets};
88
use bevy_ecs::{Resources, World};
9-
use bevy_utils::{AHashExt, HashSet};
9+
use bevy_utils::HashSet;
1010

1111
#[derive(Default)]
1212
pub struct TextureCopyNode {
@@ -24,7 +24,7 @@ impl Node for TextureCopyNode {
2424
) {
2525
let texture_events = resources.get::<Events<AssetEvent<Texture>>>().unwrap();
2626
let textures = resources.get::<Assets<Texture>>().unwrap();
27-
let mut copied_textures = HashSet::new();
27+
let mut copied_textures = HashSet::default();
2828
for event in self.texture_event_reader.iter(&texture_events) {
2929
match event {
3030
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {

crates/bevy_text/src/font_atlas_set.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use bevy_math::Vec2;
66
use bevy_reflect::TypeUuid;
77
use bevy_render::texture::Texture;
88
use bevy_sprite::TextureAtlas;
9-
use bevy_utils::{AHashExt, HashMap};
9+
use bevy_utils::HashMap;
1010

1111
type FontSizeKey = FloatOrd;
1212

@@ -25,7 +25,7 @@ pub struct GlyphAtlasInfo {
2525
impl Default for FontAtlasSet {
2626
fn default() -> Self {
2727
FontAtlasSet {
28-
font_atlases: HashMap::with_capacity(1),
28+
font_atlases: HashMap::with_capacity_and_hasher(1, Default::default()),
2929
}
3030
}
3131
}

crates/bevy_utils/src/lib.rs

Lines changed: 29 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -11,89 +11,45 @@ pub type BoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
1111
#[cfg(target_arch = "wasm32")]
1212
pub type BoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
1313

14+
/// A hasher builder that will create a fixed hasher.
15+
#[derive(Default)]
16+
pub struct FixedState;
17+
18+
impl std::hash::BuildHasher for FixedState {
19+
type Hasher = AHasher;
20+
21+
#[inline]
22+
fn build_hasher(&self) -> AHasher {
23+
AHasher::new_with_keys(0, 0)
24+
}
25+
}
26+
1427
/// A std hash map implementing AHash, a high speed keyed hashing algorithm
1528
/// intended for use in in-memory hashmaps.
1629
///
1730
/// AHash is designed for performance and is NOT cryptographically secure.
1831
pub type HashMap<K, V> = std::collections::HashMap<K, V, RandomState>;
1932

20-
pub trait AHashExt {
21-
fn new() -> Self;
22-
23-
fn with_capacity(capacity: usize) -> Self;
24-
}
25-
26-
impl<K, V> AHashExt for HashMap<K, V> {
27-
/// Creates an empty `HashMap` with AHash.
28-
///
29-
/// The hash map is initially created with a capacity of 0, so it will not
30-
/// allocate until it is first inserted into.
31-
///
32-
/// # Examples
33-
///
34-
/// ```
35-
/// use bevy_utils::{HashMap, AHashExt};
36-
/// let mut map: HashMap<&str, i32> = HashMap::new();
37-
/// ```
38-
#[inline]
39-
fn new() -> Self {
40-
Default::default()
41-
}
42-
43-
/// Creates an empty `HashMap` with the specified capacity with AHash.
44-
///
45-
/// The hash map will be able to hold at least `capacity` elements without
46-
/// reallocating. If `capacity` is 0, the hash map will not allocate.
47-
///
48-
/// # Examples
49-
///
50-
/// ```
51-
/// use bevy_utils::{HashMap, AHashExt};
52-
/// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10);
53-
/// ```
54-
#[inline]
55-
fn with_capacity(capacity: usize) -> Self {
56-
HashMap::with_capacity_and_hasher(capacity, RandomState::default())
57-
}
58-
}
33+
/// A stable std hash map implementing AHash, a high speed keyed hashing algorithm
34+
/// intended for use in in-memory hashmaps.
35+
///
36+
/// Unlike [`HashMap`] this has an iteration order that only depends on the order
37+
/// of insertions and deletions and not a random source.
38+
///
39+
/// AHash is designed for performance and is NOT cryptographically secure.
40+
pub type StableHashMap<K, V> = std::collections::HashMap<K, V, FixedState>;
5941

6042
/// A std hash set implementing AHash, a high speed keyed hashing algorithm
6143
/// intended for use in in-memory hashmaps.
6244
///
6345
/// AHash is designed for performance and is NOT cryptographically secure.
6446
pub type HashSet<K> = std::collections::HashSet<K, RandomState>;
6547

66-
impl<K> AHashExt for HashSet<K> {
67-
/// Creates an empty `HashSet` with AHash.
68-
///
69-
/// The hash set is initially created with a capacity of 0, so it will not
70-
/// allocate until it is first inserted into.
71-
///
72-
/// # Examples
73-
///
74-
/// ```
75-
/// use bevy_utils::{HashSet, AHashExt};
76-
/// let set: HashSet<i32> = HashSet::new();
77-
/// ```
78-
#[inline]
79-
fn new() -> Self {
80-
Default::default()
81-
}
82-
83-
/// Creates an empty `HashSet` with the specified capacity with AHash.
84-
///
85-
/// The hash set will be able to hold at least `capacity` elements without
86-
/// reallocating. If `capacity` is 0, the hash set will not allocate.
87-
///
88-
/// # Examples
89-
///
90-
/// ```
91-
/// use bevy_utils::{HashSet, AHashExt};
92-
/// let set: HashSet<i32> = HashSet::with_capacity(10);
93-
/// assert!(set.capacity() >= 10);
94-
/// ```
95-
#[inline]
96-
fn with_capacity(capacity: usize) -> Self {
97-
HashSet::with_capacity_and_hasher(capacity, RandomState::default())
98-
}
99-
}
48+
/// A stable std hash set implementing AHash, a high speed keyed hashing algorithm
49+
/// intended for use in in-memory hashmaps.
50+
///
51+
/// Unlike [`HashSet`] this has an iteration order that only depends on the order
52+
/// of insertions and deletions and not a random source.
53+
///
54+
/// AHash is designed for performance and is NOT cryptographically secure.
55+
pub type StableHashSet<K> = std::collections::HashSet<K, FixedState>;

0 commit comments

Comments
 (0)