Skip to content

Commit 5690242

Browse files
committed
Add MemoryStats and docs, docs, docs!
1 parent ff37883 commit 5690242

File tree

8 files changed

+155
-31
lines changed

8 files changed

+155
-31
lines changed

examples/components.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use bevy::prelude::*;
2+
23
use bevy_datasize::{DataSize, MemoryUsage, MemoryUsagePlugin, RegisterSizedTypes};
34

45
#[derive(Component, DataSize)]
@@ -24,7 +25,7 @@ fn spawn_entities(mut commands: Commands) {
2425
}
2526

2627
fn print_size(memory_usage: Res<MemoryUsage>) {
27-
let bytes = memory_usage.get_usage::<MyComponent>().unwrap();
28+
let stats = memory_usage.get_stats::<MyComponent>().unwrap();
2829

29-
println!("Memory usage: {} bytes", bytes);
30+
println!("Memory usage: {:#?}", stats);
3031
}

src/app_ext.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@ use std::any::Any;
33
use bevy::app::App;
44
use bevy::ecs::component::Component;
55

6-
use crate::{systems::update_datasize_for_component, DataSize, MemoryUsage};
6+
use crate::{systems::update_stats_for_component, DataSize, MemoryUsage};
77

8+
/// [`App`] extension methods to register types for memory usage tracking.
89
pub trait RegisterSizedTypes {
10+
/// Registers the given [`Component`] type with the
11+
/// [`MemoryUsagePlugin`][crate::MemoryUsagePlugin].
12+
///
13+
/// The given type `T` will be available to query on the [`MemoryUsage`]
14+
/// resource.
915
fn register_sized_component<T>(&mut self) -> &mut Self
1016
where
1117
T: Any + Component + DataSize;
@@ -22,7 +28,7 @@ impl RegisterSizedTypes for App {
2228

2329
memory_usage.register_type::<T>();
2430

25-
self.add_system(update_datasize_for_component::<T>);
31+
self.add_system(update_stats_for_component::<T>);
2632

2733
self
2834
}

src/config.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1+
/// Configuration for the [`MemoryUsagePlugin`][crate::MemoryUsagePlugin].
12
#[derive(Debug)]
23
pub struct MemoryConfig {
3-
pub tracking_enabled: bool,
4+
/// Whether to track memory usage for all registered types.
5+
pub global: bool,
46
}
57

68
impl Default for MemoryConfig {
79
fn default() -> Self {
8-
Self {
9-
tracking_enabled: true,
10-
}
10+
Self { global: true }
1111
}
1212
}

src/lib.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
#![doc = include_str!("../README.md")]
2+
#![warn(missing_docs)]
23

34
pub use datasize::DataSize;
45

56
mod app_ext;
67
mod config;
78
mod plugin;
89
mod resource;
9-
mod systems;
10+
mod stats;
11+
pub mod systems;
1012

1113
pub use app_ext::RegisterSizedTypes;
1214
pub use config::MemoryConfig;
1315
pub use plugin::MemoryUsagePlugin;
1416
pub use resource::MemoryUsage;
15-
16-
pub fn estimate_stack_and_heap_size<T>(value: &T) -> usize
17-
where
18-
T: DataSize,
19-
{
20-
let stack_size = std::mem::size_of::<T>();
21-
let heap_size = value.estimate_heap_size();
22-
23-
stack_size + heap_size
24-
}
17+
pub use stats::MemoryStats;

src/plugin.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ use bevy::app::Plugin;
22

33
use crate::{MemoryConfig, MemoryUsage};
44

5+
/// Adds memory usage tracking to Apps.
6+
///
7+
/// You can configure this plugin using the [`MemoryConfig`] resource.
58
pub struct MemoryUsagePlugin;
69

710
impl Plugin for MemoryUsagePlugin {

src/resource.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,29 @@ use std::any::{Any, TypeId};
22

33
use bevy::utils::HashMap;
44

5+
use crate::MemoryStats;
6+
7+
/// Stores memory usage statistics for registered data types.
58
#[derive(Debug, Default)]
69
pub struct MemoryUsage {
7-
pub(crate) datasizes: HashMap<TypeId, usize>,
10+
pub(crate) datasizes: HashMap<TypeId, MemoryStats>,
811
}
912

1013
impl MemoryUsage {
11-
pub fn register_type<T>(&mut self)
14+
/// Returns the most recent [`MemoryStats`] for the given type.
15+
///
16+
/// Returns `None` if the type has not been registered.
17+
pub fn get_stats<T>(&self) -> Option<MemoryStats>
1218
where
1319
T: Any,
1420
{
1521
let type_id = TypeId::of::<T>();
1622

17-
self.datasizes.insert(type_id, 0);
23+
self.datasizes.get(&type_id).copied()
1824
}
1925

20-
pub fn update_usage<T>(&mut self, total_bytes: usize)
26+
/// Updates the [`MemoryStats`] for the given type.
27+
pub fn update_stats<T>(&mut self, stats: MemoryStats)
2128
where
2229
T: Any,
2330
{
@@ -28,15 +35,16 @@ impl MemoryUsage {
2835
.get_mut(&type_id)
2936
.expect("Memory usage not tracked for this type. Did you forget to register the type?");
3037

31-
*entry = total_bytes;
38+
*entry = stats;
3239
}
3340

34-
pub fn get_usage<T>(&self) -> Option<usize>
41+
/// Registers the given type with the usage tracker.
42+
pub fn register_type<T>(&mut self)
3543
where
3644
T: Any,
3745
{
3846
let type_id = TypeId::of::<T>();
3947

40-
self.datasizes.get(&type_id).copied()
48+
self.datasizes.insert(type_id, Default::default());
4149
}
4250
}

src/stats.rs

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
use std::any::Any;
2+
3+
use crate::DataSize;
4+
5+
/// Memory usage statistics for a single data type.
6+
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
7+
pub struct MemoryStats {
8+
/// The total number of instances of this data type.
9+
pub count: usize,
10+
11+
/// The total number of "stack" bytes used by instances of this data type.
12+
///
13+
/// See [`stack_size_of`] for details on the meaning of this quantity.
14+
///
15+
/// [`stack_size_of`]: Self::stack_size_of
16+
pub total_stack_bytes: usize,
17+
18+
/// The estimated total number of bytes used by instances of this data type.
19+
///
20+
/// See [`heap_size_of`] for details on the meaning of this quantity.
21+
///
22+
/// [`heap_size_of`]: Self::heap_size_of
23+
pub total_heap_bytes: usize,
24+
}
25+
26+
impl MemoryStats {
27+
/// Returns the sum of `total_stack_bytes` and `total_heap_bytes` for
28+
/// `self`.
29+
#[inline]
30+
pub fn total_bytes(&self) -> usize {
31+
self.total_stack_bytes + self.total_heap_bytes
32+
}
33+
34+
/// Returns the computed memory statistics for a single value.
35+
#[inline]
36+
pub fn from_value<T>(value: &T) -> Self
37+
where
38+
T: Any + DataSize,
39+
{
40+
Self {
41+
count: 1,
42+
total_stack_bytes: Self::stack_size_of(value),
43+
total_heap_bytes: Self::heap_size_of(value),
44+
}
45+
}
46+
47+
/// Returns the computed memory statistics for a collection of values.
48+
#[inline]
49+
pub fn from_values<'a, T, I>(values: I) -> Self
50+
where
51+
T: Any + DataSize,
52+
I: IntoIterator<Item = &'a T>,
53+
{
54+
let mut count = 0;
55+
let mut total_stack_bytes = 0;
56+
let mut total_heap_bytes = 0;
57+
58+
for value in values.into_iter() {
59+
count += 1;
60+
total_stack_bytes += Self::stack_size_of(value);
61+
total_heap_bytes += Self::heap_size_of(value);
62+
}
63+
64+
Self {
65+
count,
66+
total_stack_bytes,
67+
total_heap_bytes,
68+
}
69+
}
70+
71+
/// Returns the "stack" size of the given value.
72+
///
73+
/// This quantity represents how many bytes the type *would* take up on the
74+
/// stack if were allocated there.
75+
///
76+
/// This quantity is **exact** and is computed using [`std::mem::size_of`].
77+
#[inline]
78+
pub fn stack_size_of<T>(value: &T) -> usize
79+
where
80+
T: Any,
81+
{
82+
std::mem::size_of_val(value)
83+
}
84+
85+
/// Returns the estimated heap size of the given value.
86+
///
87+
/// This quantity represents how many bytes the type occupies apart from the
88+
/// immediate bytes of its fields.
89+
#[inline]
90+
pub fn heap_size_of<T>(value: &T) -> usize
91+
where
92+
T: DataSize,
93+
{
94+
value.estimate_heap_size()
95+
}
96+
97+
/// Returns the estimated total size of the given value.
98+
///
99+
/// This quantity is the sum of [`stack_size_of`] and [`heap_size_of`].
100+
///
101+
/// [`stack_size_of`]: Self::stack_size_of
102+
/// [`heap_size_of`]: Self::heap_size_of
103+
pub fn total_size_of<T>(value: &T) -> usize
104+
where
105+
T: Any + DataSize,
106+
{
107+
Self::stack_size_of(value) + Self::heap_size_of(value)
108+
}
109+
}

src/systems.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
1+
//! Systems used by this library.
2+
13
use std::any::Any;
24

35
use bevy::prelude::*;
46
use datasize::DataSize;
57

6-
use crate::{estimate_stack_and_heap_size, MemoryConfig, MemoryUsage};
8+
use crate::{MemoryConfig, MemoryStats, MemoryUsage};
79

8-
pub fn update_datasize_for_component<T>(
10+
/// This system iterates through all components of type `T` and updates their
11+
/// [`MemoryStats`].
12+
pub fn update_stats_for_component<T>(
913
query: Query<&T>,
1014
memory_config: Res<MemoryConfig>,
1115
mut memory_usage: ResMut<MemoryUsage>,
1216
) where
1317
T: Any + Component + DataSize,
1418
{
15-
if !memory_config.tracking_enabled {
19+
if !memory_config.global {
1620
return;
1721
}
1822

19-
let total_bytes: usize = query.iter().map(estimate_stack_and_heap_size).sum();
23+
let stats = MemoryStats::from_values(query.iter());
2024

21-
memory_usage.update_usage::<T>(total_bytes);
25+
memory_usage.update_stats::<T>(stats);
2226
}

0 commit comments

Comments
 (0)