bevy_render/diagnostic/
mesh_allocator_diagnostic_plugin.rs

1use bevy_app::{Plugin, PreUpdate};
2use bevy_diagnostic::{Diagnostic, DiagnosticPath, Diagnostics, RegisterDiagnostic};
3use bevy_ecs::{resource::Resource, system::Res};
4use bevy_platform::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
5
6use crate::{mesh::allocator::MeshAllocator, Extract, ExtractSchedule, RenderApp};
7
8/// Number of meshes allocated by the allocator
9static MESH_ALLOCATOR_SLABS: DiagnosticPath = DiagnosticPath::const_new("mesh_allocator_slabs");
10
11/// Total size of all slabs
12static MESH_ALLOCATOR_SLABS_SIZE: DiagnosticPath =
13    DiagnosticPath::const_new("mesh_allocator_slabs_size");
14
15/// Number of meshes allocated into slabs
16static MESH_ALLOCATOR_ALLOCATIONS: DiagnosticPath =
17    DiagnosticPath::const_new("mesh_allocator_allocations");
18
19pub struct MeshAllocatorDiagnosticPlugin;
20
21impl MeshAllocatorDiagnosticPlugin {
22    /// Get the [`DiagnosticPath`] for slab count
23    pub fn slabs_diagnostic_path() -> &'static DiagnosticPath {
24        &MESH_ALLOCATOR_SLABS
25    }
26    /// Get the [`DiagnosticPath`] for total slabs size
27    pub fn slabs_size_diagnostic_path() -> &'static DiagnosticPath {
28        &MESH_ALLOCATOR_SLABS_SIZE
29    }
30    /// Get the [`DiagnosticPath`] for mesh allocations
31    pub fn allocations_diagnostic_path() -> &'static DiagnosticPath {
32        &MESH_ALLOCATOR_ALLOCATIONS
33    }
34}
35
36impl Plugin for MeshAllocatorDiagnosticPlugin {
37    fn build(&self, app: &mut bevy_app::App) {
38        app.register_diagnostic(
39            Diagnostic::new(MESH_ALLOCATOR_SLABS.clone()).with_suffix(" slabs"),
40        )
41        .register_diagnostic(
42            Diagnostic::new(MESH_ALLOCATOR_SLABS_SIZE.clone()).with_suffix(" bytes"),
43        )
44        .register_diagnostic(
45            Diagnostic::new(MESH_ALLOCATOR_ALLOCATIONS.clone()).with_suffix(" meshes"),
46        )
47        .init_resource::<MeshAllocatorMeasurements>()
48        .add_systems(PreUpdate, add_mesh_allocator_measurement);
49
50        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
51            render_app.add_systems(ExtractSchedule, measure_allocator);
52        }
53    }
54}
55
56#[derive(Debug, Default, Resource)]
57struct MeshAllocatorMeasurements {
58    slabs: AtomicUsize,
59    slabs_size: AtomicU64,
60    allocations: AtomicUsize,
61}
62
63fn add_mesh_allocator_measurement(
64    mut diagnostics: Diagnostics,
65    measurements: Res<MeshAllocatorMeasurements>,
66) {
67    diagnostics.add_measurement(&MESH_ALLOCATOR_SLABS, || {
68        measurements.slabs.load(Ordering::Relaxed) as f64
69    });
70    diagnostics.add_measurement(&MESH_ALLOCATOR_SLABS_SIZE, || {
71        measurements.slabs_size.load(Ordering::Relaxed) as f64
72    });
73    diagnostics.add_measurement(&MESH_ALLOCATOR_ALLOCATIONS, || {
74        measurements.allocations.load(Ordering::Relaxed) as f64
75    });
76}
77
78fn measure_allocator(
79    measurements: Extract<Res<MeshAllocatorMeasurements>>,
80    allocator: Res<MeshAllocator>,
81) {
82    measurements
83        .slabs
84        .store(allocator.slab_count(), Ordering::Relaxed);
85    measurements
86        .slabs_size
87        .store(allocator.slabs_size(), Ordering::Relaxed);
88    measurements
89        .allocations
90        .store(allocator.allocations(), Ordering::Relaxed);
91}