Skip to content

Commit a1af984

Browse files
committed
Introduce DataSizeEstimator trait in preparation for supporting bevy builtins.
1 parent b4cab24 commit a1af984

File tree

5 files changed

+105
-58
lines changed

5 files changed

+105
-58
lines changed

src/app_ext.rs

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ use std::any::Any;
33
use bevy::{
44
app::App,
55
asset::Asset,
6-
ecs::{component::Component, system::Resource},
6+
ecs::{component::Component, schedule::IntoSystemDescriptor, system::Resource},
77
};
88

9-
use crate::{systems, DataSize, MemoryUsage};
9+
use crate::{systems, DataSize, DataSizeEstimator, MemoryUsage};
1010

1111
/// [`App`] extension methods to register types for memory usage tracking.
1212
pub trait RegisterSizedTypes {
@@ -17,7 +17,10 @@ pub trait RegisterSizedTypes {
1717
/// resource.
1818
fn register_sized_component<T>(&mut self) -> &mut Self
1919
where
20-
T: Any + DataSize + Component;
20+
T: Any + DataSize + Component,
21+
{
22+
self.register_sized_type::<T, T, _, _>(systems::update_stats_for_component::<T, T>)
23+
}
2124

2225
/// Registers the given [`Resource`] type with the
2326
/// [`MemoryUsagePlugin`][crate::MemoryUsagePlugin].
@@ -26,7 +29,10 @@ pub trait RegisterSizedTypes {
2629
/// resource.
2730
fn register_sized_resource<T>(&mut self) -> &mut Self
2831
where
29-
T: Any + DataSize + Resource;
32+
T: Any + DataSize + Resource,
33+
{
34+
self.register_sized_type::<T, T, _, _>(systems::update_stats_for_resource::<T, T>)
35+
}
3036

3137
/// Registers the given [`Asset`] type with the
3238
/// [`MemoryUsagePlugin`][crate::MemoryUsagePlugin].
@@ -35,47 +41,38 @@ pub trait RegisterSizedTypes {
3541
/// resource.
3642
fn register_sized_asset<T>(&mut self) -> &mut Self
3743
where
38-
T: Any + DataSize + Asset;
39-
}
40-
41-
impl RegisterSizedTypes for App {
42-
fn register_sized_component<T>(&mut self) -> &mut Self
43-
where
44-
T: Any + Component + DataSize,
44+
T: Any + DataSize + Asset,
4545
{
46-
register_type::<T>(self);
47-
48-
self.add_system(systems::update_stats_for_component::<T>);
49-
50-
self
46+
self.register_sized_type::<T, T, _, _>(systems::update_stats_for_asset::<T, T>)
5147
}
5248

53-
fn register_sized_resource<T>(&mut self) -> &mut Self
49+
/// Registers a type that can be sized with the given [`DataSizeEstimator`]
50+
/// type and updated using the provided `system`.
51+
fn register_sized_type<T, E, S, Params>(&mut self, system: S) -> &mut Self
5452
where
55-
T: Any + DataSize + Resource,
56-
{
57-
register_type::<T>(self);
58-
59-
self.add_system(systems::update_stats_for_resource::<T>);
60-
61-
self
62-
}
53+
T: Any,
54+
E: DataSizeEstimator<T>,
55+
S: IntoSystemDescriptor<Params>;
56+
}
6357

64-
fn register_sized_asset<T>(&mut self) -> &mut Self
58+
impl RegisterSizedTypes for App {
59+
fn register_sized_type<T, E, S, Params>(&mut self, system: S) -> &mut Self
6560
where
66-
T: Any + DataSize + Asset,
61+
T: Any,
62+
E: DataSizeEstimator<T>,
63+
S: IntoSystemDescriptor<Params>,
6764
{
6865
register_type::<T>(self);
6966

70-
self.add_system(systems::update_stats_for_asset::<T>);
67+
self.add_system(system);
7168

7269
self
7370
}
7471
}
7572

7673
fn register_type<T>(app: &mut App)
7774
where
78-
T: Any + DataSize,
75+
T: Any,
7976
{
8077
let mut memory_usage = app.world.get_resource_mut::<MemoryUsage>().expect(
8178
"Cannot find resource `MemoryUsage`. Did you forget to add the `MemoryUsagePlugin`?",

src/estimator.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use crate::DataSize;
2+
3+
/// Indicates that a type can estimate the heap usage of values of type `T`.
4+
///
5+
/// All types which implement [`DataSize`] have this trait implemented on
6+
/// themselves.
7+
///
8+
/// This trait exists in order to work around the fact that this crate cannot
9+
/// add impls of [`DataSize`] to types from the Bevy crate(s).
10+
pub trait DataSizeEstimator<T> {
11+
/// Estimates the size of heap memory taken up by the given value.
12+
///
13+
/// Does not include data on the stack, which is usually determined using
14+
/// [`std::mem::size_of`].
15+
fn estimate_heap_size(value: &T) -> usize;
16+
}
17+
18+
impl<T: DataSize> DataSizeEstimator<T> for T {
19+
fn estimate_heap_size(value: &T) -> usize {
20+
<T as DataSize>::estimate_heap_size(value)
21+
}
22+
}

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,17 @@ pub use datasize;
4444
pub use datasize::DataSize;
4545

4646
mod app_ext;
47+
pub mod builtins;
4748
mod config;
49+
mod estimator;
4850
mod plugin;
4951
mod resource;
5052
mod stats;
5153
pub mod systems;
5254

5355
pub use app_ext::RegisterSizedTypes;
5456
pub use config::MemoryConfig;
57+
pub use estimator::DataSizeEstimator;
5558
pub use plugin::MemoryUsagePlugin;
5659
pub use resource::MemoryUsage;
5760
pub use stats::MemoryStats;

src/stats.rs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{
33
sync::atomic::{AtomicUsize, Ordering},
44
};
55

6-
use crate::DataSize;
6+
use crate::{DataSize, DataSizeEstimator};
77

88
/// Memory usage statistics for a single data type.
99
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
@@ -39,11 +39,22 @@ impl MemoryStats {
3939
pub fn from_value<T>(value: &T) -> Self
4040
where
4141
T: Any + DataSize,
42+
{
43+
Self::from_value_with_estimator::<T, T>(value)
44+
}
45+
46+
/// Returns the computed memory statistics for a single value using a
47+
/// specific [`DataSizeEstimator`].
48+
#[inline]
49+
pub fn from_value_with_estimator<T, E>(value: &T) -> Self
50+
where
51+
T: Any,
52+
E: DataSizeEstimator<T>,
4253
{
4354
Self {
4455
count: 1,
4556
total_stack_bytes: Self::stack_size_of(value),
46-
total_heap_bytes: Self::heap_size_of(value),
57+
total_heap_bytes: Self::heap_size_of_with_estimator::<T, E>(value),
4758
}
4859
}
4960

@@ -53,6 +64,17 @@ impl MemoryStats {
5364
where
5465
T: Any + DataSize,
5566
I: IntoIterator<Item = &'a T>,
67+
{
68+
Self::from_values_with_estimator::<T, T, I>(values)
69+
}
70+
71+
/// Returns the computed memory statistics for a collection of values.
72+
#[inline]
73+
pub fn from_values_with_estimator<'a, T, E, I>(values: I) -> Self
74+
where
75+
T: Any,
76+
E: DataSizeEstimator<T>,
77+
I: IntoIterator<Item = &'a T>,
5678
{
5779
let mut count = 0;
5880
let mut total_stack_bytes = 0;
@@ -61,7 +83,7 @@ impl MemoryStats {
6183
for value in values.into_iter() {
6284
count += 1;
6385
total_stack_bytes += Self::stack_size_of(value);
64-
total_heap_bytes += Self::heap_size_of(value);
86+
total_heap_bytes += Self::heap_size_of_with_estimator::<T, E>(value);
6587
}
6688

6789
Self {
@@ -94,20 +116,17 @@ impl MemoryStats {
94116
where
95117
T: DataSize,
96118
{
97-
value.estimate_heap_size()
119+
Self::heap_size_of_with_estimator::<T, T>(value)
98120
}
99121

100-
/// Returns the estimated total size of the given value.
101-
///
102-
/// This quantity is the sum of [`stack_size_of`] and [`heap_size_of`].
103-
///
104-
/// [`stack_size_of`]: Self::stack_size_of
105-
/// [`heap_size_of`]: Self::heap_size_of
106-
pub fn total_size_of<T>(value: &T) -> usize
122+
/// Returns the estimated heap size of the given value using a specific
123+
/// [`DataSizeEstimator`].
124+
#[inline]
125+
pub fn heap_size_of_with_estimator<T, E>(value: &T) -> usize
107126
where
108-
T: Any + DataSize,
127+
E: DataSizeEstimator<T>,
109128
{
110-
Self::stack_size_of(value) + Self::heap_size_of(value)
129+
<E as DataSizeEstimator<T>>::estimate_heap_size(value)
111130
}
112131
}
113132

src/systems.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,53 +9,59 @@ use bevy::{
99
system::{Query, Res, Resource},
1010
},
1111
};
12-
use datasize::DataSize;
1312

14-
use crate::{MemoryConfig, MemoryStats, MemoryUsage};
13+
use crate::{DataSizeEstimator, MemoryConfig, MemoryStats, MemoryUsage};
1514

16-
/// This system iterates through all components of type `T` and updates their
17-
/// [`MemoryStats`].
18-
pub fn update_stats_for_component<T>(
15+
/// This system updates the [`MemoryStats`] for the given component type `T`
16+
/// using the given [`DataSizeEstimator`].
17+
pub fn update_stats_for_component<T, E>(
1918
query: Query<&T>,
2019
memory_config: Res<MemoryConfig>,
2120
memory_usage: Res<MemoryUsage>,
2221
) where
23-
T: Any + Component + DataSize,
22+
T: Any + Component,
23+
E: DataSizeEstimator<T>,
2424
{
2525
update_stats::<T, _>(memory_config, memory_usage, || {
26-
MemoryStats::from_values(query.iter())
26+
MemoryStats::from_values_with_estimator::<T, E, _>(query.iter())
2727
});
2828
}
2929

30-
/// This system updates the [`MemoryStats`] for the given resource type `T`.
31-
pub fn update_stats_for_resource<T>(
30+
/// This system updates the [`MemoryStats`] for the given resource type `T`
31+
/// using the given [`DataSizeEstimator`].
32+
pub fn update_stats_for_resource<T, E>(
3233
resource: Res<T>,
3334
memory_config: Res<MemoryConfig>,
3435
memory_usage: Res<MemoryUsage>,
3536
) where
36-
T: Any + DataSize + Resource,
37+
T: Any + Resource,
38+
E: DataSizeEstimator<T>,
3739
{
3840
update_stats::<T, _>(memory_config, memory_usage, || {
39-
MemoryStats::from_value(&*resource)
41+
MemoryStats::from_value_with_estimator::<T, E>(&*resource)
4042
});
4143
}
4244

43-
/// This system updates the [`MemoryStats`] for the given asset type `T`.
44-
pub fn update_stats_for_asset<T>(
45+
/// This system updates the [`MemoryStats`] for the given asset type `T`
46+
/// using the given [`DataSizeEstimator`].
47+
pub fn update_stats_for_asset<T, E>(
4548
assets: Res<Assets<T>>,
4649
memory_config: Res<MemoryConfig>,
4750
memory_usage: Res<MemoryUsage>,
4851
) where
49-
T: Any + DataSize + Asset,
52+
T: Any + Asset,
53+
E: DataSizeEstimator<T>,
5054
{
5155
update_stats::<T, _>(memory_config, memory_usage, || {
52-
MemoryStats::from_values(assets.iter().map(|(_handle, asset)| asset))
56+
MemoryStats::from_values_with_estimator::<T, E, _>(
57+
assets.iter().map(|(_handle, asset)| asset),
58+
)
5359
});
5460
}
5561

5662
fn update_stats<T, F>(memory_config: Res<MemoryConfig>, memory_usage: Res<MemoryUsage>, op: F)
5763
where
58-
T: Any + DataSize,
64+
T: Any,
5965
F: FnOnce() -> MemoryStats,
6066
{
6167
if !memory_config.global {

0 commit comments

Comments
 (0)