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 ```
This commit is contained in:
		
							parent
							
								
									c434f57de1
								
							
						
					
					
						commit
						fbf08ac545
					
				@ -1,5 +1,5 @@
 | 
			
		||||
use bevy_utils::{Duration, HashMap, Instant, Uuid};
 | 
			
		||||
use std::collections::{BTreeSet, VecDeque};
 | 
			
		||||
use bevy_utils::{Duration, Instant, StableHashMap, Uuid};
 | 
			
		||||
use std::collections::VecDeque;
 | 
			
		||||
 | 
			
		||||
/// Unique identifier for a [Diagnostic]
 | 
			
		||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
 | 
			
		||||
@ -101,13 +101,13 @@ impl Diagnostic {
 | 
			
		||||
/// A collection of [Diagnostic]s
 | 
			
		||||
#[derive(Debug, Default)]
 | 
			
		||||
pub struct Diagnostics {
 | 
			
		||||
    diagnostics: HashMap<DiagnosticId, Diagnostic>,
 | 
			
		||||
    ordered_diagnostics: BTreeSet<DiagnosticId>,
 | 
			
		||||
    // This uses a [`StableHashMap`] to ensure that the iteration order is deterministic between
 | 
			
		||||
    // runs when all diagnostics are inserted in the same order.
 | 
			
		||||
    diagnostics: StableHashMap<DiagnosticId, Diagnostic>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Diagnostics {
 | 
			
		||||
    pub fn add(&mut self, diagnostic: Diagnostic) {
 | 
			
		||||
        self.ordered_diagnostics.insert(diagnostic.id);
 | 
			
		||||
        self.diagnostics.insert(diagnostic.id, diagnostic);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -134,10 +134,4 @@ impl Diagnostics {
 | 
			
		||||
    pub fn iter(&self) -> impl Iterator<Item = &Diagnostic> {
 | 
			
		||||
        self.diagnostics.values()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn ordered_iter(&self) -> impl Iterator<Item = &Diagnostic> {
 | 
			
		||||
        self.ordered_diagnostics
 | 
			
		||||
            .iter()
 | 
			
		||||
            .filter_map(move |k| self.diagnostics.get(k))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -78,7 +78,7 @@ impl LogDiagnosticsPlugin {
 | 
			
		||||
                    Self::log_diagnostic(diagnostic);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                for diagnostic in diagnostics.ordered_iter() {
 | 
			
		||||
                for diagnostic in diagnostics.iter() {
 | 
			
		||||
                    Self::log_diagnostic(diagnostic);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -96,7 +96,7 @@ impl LogDiagnosticsPlugin {
 | 
			
		||||
                    debug!("{:#?}\n", diagnostic);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                for diagnostic in diagnostics.ordered_iter() {
 | 
			
		||||
                for diagnostic in diagnostics.iter() {
 | 
			
		||||
                    debug!("{:#?}\n", diagnostic);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
use bevy_utils::{AHashExt, HashMap};
 | 
			
		||||
use bevy_utils::HashMap;
 | 
			
		||||
use std::hash::Hash;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
@ -12,7 +12,7 @@ where
 | 
			
		||||
{
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Axis {
 | 
			
		||||
            axis_data: HashMap::new(),
 | 
			
		||||
            axis_data: HashMap::default(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ use crate::{
 | 
			
		||||
use bevy_app::prelude::{EventReader, Events};
 | 
			
		||||
use bevy_asset::{AssetEvent, Assets};
 | 
			
		||||
use bevy_ecs::{Resources, World};
 | 
			
		||||
use bevy_utils::{AHashExt, HashSet};
 | 
			
		||||
use bevy_utils::HashSet;
 | 
			
		||||
 | 
			
		||||
#[derive(Default)]
 | 
			
		||||
pub struct TextureCopyNode {
 | 
			
		||||
@ -24,7 +24,7 @@ impl Node for TextureCopyNode {
 | 
			
		||||
    ) {
 | 
			
		||||
        let texture_events = resources.get::<Events<AssetEvent<Texture>>>().unwrap();
 | 
			
		||||
        let textures = resources.get::<Assets<Texture>>().unwrap();
 | 
			
		||||
        let mut copied_textures = HashSet::new();
 | 
			
		||||
        let mut copied_textures = HashSet::default();
 | 
			
		||||
        for event in self.texture_event_reader.iter(&texture_events) {
 | 
			
		||||
            match event {
 | 
			
		||||
                AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ use bevy_math::Vec2;
 | 
			
		||||
use bevy_reflect::TypeUuid;
 | 
			
		||||
use bevy_render::texture::Texture;
 | 
			
		||||
use bevy_sprite::TextureAtlas;
 | 
			
		||||
use bevy_utils::{AHashExt, HashMap};
 | 
			
		||||
use bevy_utils::HashMap;
 | 
			
		||||
 | 
			
		||||
type FontSizeKey = FloatOrd;
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@ pub struct GlyphAtlasInfo {
 | 
			
		||||
impl Default for FontAtlasSet {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        FontAtlasSet {
 | 
			
		||||
            font_atlases: HashMap::with_capacity(1),
 | 
			
		||||
            font_atlases: HashMap::with_capacity_and_hasher(1, Default::default()),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,51 +11,33 @@ pub type BoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
 | 
			
		||||
#[cfg(target_arch = "wasm32")]
 | 
			
		||||
pub type BoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
 | 
			
		||||
 | 
			
		||||
/// A hasher builder that will create a fixed hasher.
 | 
			
		||||
#[derive(Default)]
 | 
			
		||||
pub struct FixedState;
 | 
			
		||||
 | 
			
		||||
impl std::hash::BuildHasher for FixedState {
 | 
			
		||||
    type Hasher = AHasher;
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn build_hasher(&self) -> AHasher {
 | 
			
		||||
        AHasher::new_with_keys(0, 0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A std hash map implementing AHash, a high speed keyed hashing algorithm
 | 
			
		||||
/// intended for use in in-memory hashmaps.
 | 
			
		||||
///
 | 
			
		||||
/// AHash is designed for performance and is NOT cryptographically secure.
 | 
			
		||||
pub type HashMap<K, V> = std::collections::HashMap<K, V, RandomState>;
 | 
			
		||||
 | 
			
		||||
pub trait AHashExt {
 | 
			
		||||
    fn new() -> Self;
 | 
			
		||||
 | 
			
		||||
    fn with_capacity(capacity: usize) -> Self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<K, V> AHashExt for HashMap<K, V> {
 | 
			
		||||
    /// Creates an empty `HashMap` with AHash.
 | 
			
		||||
    ///
 | 
			
		||||
    /// The hash map is initially created with a capacity of 0, so it will not
 | 
			
		||||
    /// allocate until it is first inserted into.
 | 
			
		||||
    ///
 | 
			
		||||
    /// # Examples
 | 
			
		||||
    ///
 | 
			
		||||
    /// ```
 | 
			
		||||
    /// use bevy_utils::{HashMap, AHashExt};
 | 
			
		||||
    /// let mut map: HashMap<&str, i32> = HashMap::new();
 | 
			
		||||
    /// ```
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Default::default()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Creates an empty `HashMap` with the specified capacity with AHash.
 | 
			
		||||
    ///
 | 
			
		||||
    /// The hash map will be able to hold at least `capacity` elements without
 | 
			
		||||
    /// reallocating. If `capacity` is 0, the hash map will not allocate.
 | 
			
		||||
    ///
 | 
			
		||||
    /// # Examples
 | 
			
		||||
    ///
 | 
			
		||||
    /// ```
 | 
			
		||||
    /// use bevy_utils::{HashMap, AHashExt};
 | 
			
		||||
    /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10);
 | 
			
		||||
    /// ```
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn with_capacity(capacity: usize) -> Self {
 | 
			
		||||
        HashMap::with_capacity_and_hasher(capacity, RandomState::default())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
/// A stable std hash map implementing AHash, a high speed keyed hashing algorithm
 | 
			
		||||
/// intended for use in in-memory hashmaps.
 | 
			
		||||
///
 | 
			
		||||
/// Unlike [`HashMap`] this has an iteration order that only depends on the order
 | 
			
		||||
/// of insertions and deletions and not a random source.
 | 
			
		||||
///
 | 
			
		||||
/// AHash is designed for performance and is NOT cryptographically secure.
 | 
			
		||||
pub type StableHashMap<K, V> = std::collections::HashMap<K, V, FixedState>;
 | 
			
		||||
 | 
			
		||||
/// A std hash set implementing AHash, a high speed keyed hashing algorithm
 | 
			
		||||
/// intended for use in in-memory hashmaps.
 | 
			
		||||
@ -63,37 +45,11 @@ impl<K, V> AHashExt for HashMap<K, V> {
 | 
			
		||||
/// AHash is designed for performance and is NOT cryptographically secure.
 | 
			
		||||
pub type HashSet<K> = std::collections::HashSet<K, RandomState>;
 | 
			
		||||
 | 
			
		||||
impl<K> AHashExt for HashSet<K> {
 | 
			
		||||
    /// Creates an empty `HashSet` with AHash.
 | 
			
		||||
    ///
 | 
			
		||||
    /// The hash set is initially created with a capacity of 0, so it will not
 | 
			
		||||
    /// allocate until it is first inserted into.
 | 
			
		||||
    ///
 | 
			
		||||
    /// # Examples
 | 
			
		||||
    ///
 | 
			
		||||
    /// ```
 | 
			
		||||
    /// use bevy_utils::{HashSet, AHashExt};
 | 
			
		||||
    /// let set: HashSet<i32> = HashSet::new();
 | 
			
		||||
    /// ```
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Default::default()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Creates an empty `HashSet` with the specified capacity with AHash.
 | 
			
		||||
    ///
 | 
			
		||||
    /// The hash set will be able to hold at least `capacity` elements without
 | 
			
		||||
    /// reallocating. If `capacity` is 0, the hash set will not allocate.
 | 
			
		||||
    ///
 | 
			
		||||
    /// # Examples
 | 
			
		||||
    ///
 | 
			
		||||
    /// ```
 | 
			
		||||
    /// use bevy_utils::{HashSet, AHashExt};
 | 
			
		||||
    /// let set: HashSet<i32> = HashSet::with_capacity(10);
 | 
			
		||||
    /// assert!(set.capacity() >= 10);
 | 
			
		||||
    /// ```
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn with_capacity(capacity: usize) -> Self {
 | 
			
		||||
        HashSet::with_capacity_and_hasher(capacity, RandomState::default())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
/// A stable std hash set implementing AHash, a high speed keyed hashing algorithm
 | 
			
		||||
/// intended for use in in-memory hashmaps.
 | 
			
		||||
///
 | 
			
		||||
/// Unlike [`HashSet`] this has an iteration order that only depends on the order
 | 
			
		||||
/// of insertions and deletions and not a random source.
 | 
			
		||||
///
 | 
			
		||||
/// AHash is designed for performance and is NOT cryptographically secure.
 | 
			
		||||
pub type StableHashSet<K> = std::collections::HashSet<K, FixedState>;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user