Skip to content

Commit e96a0d7

Browse files
authored
feat: add allocator diagnostics (#305)
1 parent b34ff20 commit e96a0d7

File tree

2 files changed

+54
-3
lines changed

2 files changed

+54
-3
lines changed

crates/bevy_mod_scripting_core/src/bindings/allocator.rs

+42-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
//! An allocator used to control the lifetime of allocations
22
3-
use bevy::{ecs::system::Resource, prelude::ResMut, reflect::PartialReflect};
3+
use bevy::{
4+
app::{App, Plugin, PostUpdate},
5+
diagnostic::{Diagnostic, DiagnosticPath, Diagnostics, RegisterDiagnostic},
6+
ecs::system::{Res, Resource},
7+
prelude::ResMut,
8+
reflect::PartialReflect,
9+
};
410
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
511
use std::{
612
cell::UnsafeCell,
@@ -11,6 +17,14 @@ use std::{
1117
sync::{atomic::AtomicU64, Arc},
1218
};
1319

20+
/// The path used for the total number of allocations diagnostic
21+
pub const ALLOCATOR_TOTAL_DIAG_PATH: DiagnosticPath =
22+
DiagnosticPath::const_new("scripting_allocator_total");
23+
24+
/// The path used for the total number of deallocated allocations diagnostic
25+
pub const ALLOCATOR_TOTAL_COLLECTED_DIAG_PATH: DiagnosticPath =
26+
DiagnosticPath::const_new("scripting_allocator_total_collected");
27+
1428
#[derive(Clone, Debug)]
1529
/// Unique identifier for an allocation
1630
pub struct ReflectAllocationId(pub(crate) Arc<u64>);
@@ -214,9 +228,34 @@ impl ReflectAllocator {
214228

215229
/// Cleans up dangling script allocations
216230
#[profiling::function]
217-
pub fn garbage_collector(allocator: ResMut<AppReflectAllocator>) {
231+
pub fn garbage_collector(allocator: ResMut<AppReflectAllocator>, mut diagnostics: Diagnostics) {
218232
let mut allocator = allocator.write();
219-
allocator.clean_garbage_allocations()
233+
let before = allocator.allocations.len();
234+
allocator.clean_garbage_allocations();
235+
let after = allocator.allocations.len();
236+
diagnostics.add_measurement(&ALLOCATOR_TOTAL_DIAG_PATH, || after as f64);
237+
diagnostics.add_measurement(&ALLOCATOR_TOTAL_COLLECTED_DIAG_PATH, || {
238+
(before - after) as f64
239+
});
240+
}
241+
242+
/// Measures the number of allocations in the allocator and other diagnostics when enabled
243+
pub fn measure_allocations(allocator: Res<AppReflectAllocator>, mut diagnostics: Diagnostics) {
244+
let allocator = allocator.read();
245+
let allocations_count = allocator.allocations.len();
246+
diagnostics.add_measurement(&ALLOCATOR_TOTAL_DIAG_PATH, || allocations_count as f64);
247+
}
248+
249+
/// A plugin which registers various allocator diagnostics
250+
pub struct AllocatorDiagnosticPlugin;
251+
impl Plugin for AllocatorDiagnosticPlugin {
252+
fn build(&self, app: &mut App) {
253+
app.register_diagnostic(Diagnostic::new(ALLOCATOR_TOTAL_DIAG_PATH).with_suffix(" allocs"))
254+
.register_diagnostic(
255+
Diagnostic::new(ALLOCATOR_TOTAL_COLLECTED_DIAG_PATH).with_suffix(" deallocs"),
256+
)
257+
.add_systems(PostUpdate, measure_allocations);
258+
}
220259
}
221260

222261
#[cfg(test)]

examples/game_of_life.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#![allow(deprecated)]
22

3+
use std::time::Duration;
4+
35
use bevy::{
6+
diagnostic::LogDiagnosticsPlugin,
47
image::ImageSampler,
58
log::LogPlugin,
69
prelude::*,
@@ -18,6 +21,7 @@ use bevy_mod_scripting_core::{
1821
bindings::{
1922
function::namespace::{GlobalNamespace, NamespaceBuilder},
2023
script_value::ScriptValue,
24+
AllocatorDiagnosticPlugin,
2125
},
2226
callback_labels,
2327
commands::AddStaticScript,
@@ -325,6 +329,14 @@ fn main() -> std::io::Result<()> {
325329
console_app(&mut app);
326330
game_of_life_app(&mut app);
327331

332+
app.add_plugins((
333+
AllocatorDiagnosticPlugin,
334+
LogDiagnosticsPlugin {
335+
wait_duration: Duration::from_secs(60),
336+
..Default::default()
337+
},
338+
));
339+
328340
app.run();
329341

330342
Ok(())

0 commit comments

Comments
 (0)