Skip to content

Commit 42b2d5e

Browse files
committed
First attempt at allocator leak detection
1 parent da17648 commit 42b2d5e

File tree

1 file changed

+95
-0
lines changed

1 file changed

+95
-0
lines changed

tests/get_mut_leak.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//! Tests if touching mutably a asset that gets extracted to the render world
2+
//! causes a leak
3+
4+
use std::time::Duration;
5+
6+
use bevy::{
7+
app::{App, PluginGroup, Startup, Update},
8+
asset::{Asset, Assets, Handle},
9+
audio::AudioPlugin,
10+
color::Color,
11+
diagnostic::{DiagnosticsStore, LogDiagnosticsPlugin},
12+
ecs::system::{Commands, Local, Res, ResMut},
13+
math::primitives::Sphere,
14+
pbr::{MeshMaterial3d, StandardMaterial},
15+
render::{
16+
diagnostic::{MeshAllocatorDiagnosticPlugin, RenderAssetDiagnosticPlugin},
17+
mesh::{Mesh, Mesh3d, Meshable, RenderMesh},
18+
},
19+
window::WindowPlugin,
20+
winit::WinitPlugin,
21+
DefaultPlugins,
22+
};
23+
24+
#[test]
25+
fn check_mesh_leak() {
26+
let mut app = App::new();
27+
app.add_plugins((
28+
DefaultPlugins
29+
.build()
30+
.disable::<AudioPlugin>()
31+
.disable::<WinitPlugin>()
32+
.disable::<WindowPlugin>(),
33+
LogDiagnosticsPlugin {
34+
wait_duration: Duration::ZERO,
35+
..Default::default()
36+
},
37+
RenderAssetDiagnosticPlugin::<RenderMesh>::new(" meshes"),
38+
MeshAllocatorDiagnosticPlugin,
39+
))
40+
.add_systems(Startup, mesh_setup)
41+
.add_systems(
42+
Update,
43+
(touch_mutably::<Mesh>, crash_on_mesh_leak_detection),
44+
);
45+
46+
app.finish();
47+
app.cleanup();
48+
49+
for _ in 0..100 {
50+
app.update();
51+
}
52+
}
53+
54+
fn mesh_setup(
55+
mut commands: Commands,
56+
mut meshes: ResMut<Assets<Mesh>>,
57+
mut materials: ResMut<Assets<StandardMaterial>>,
58+
mut mesh_leaker: Local<Vec<Handle<Mesh>>>,
59+
mut material_leaker: Local<Vec<Handle<StandardMaterial>>>,
60+
) {
61+
bevy::log::info!("Mesh setup");
62+
commands.spawn((
63+
Mesh3d(meshes.add(Sphere::new(1.).mesh().ico(79).unwrap())),
64+
MeshMaterial3d(materials.add(Color::WHITE)),
65+
));
66+
67+
for _ in 0..16 {
68+
mesh_leaker.push(meshes.add(Sphere::new(1.).mesh().ico(79).unwrap()));
69+
}
70+
for _ in 0..1000 {
71+
material_leaker.push(materials.add(Color::WHITE));
72+
}
73+
}
74+
75+
fn touch_mutably<A: Asset>(mut assets: ResMut<Assets<A>>) {
76+
for _ in assets.iter_mut() {}
77+
}
78+
79+
fn crash_on_mesh_leak_detection(diagnostic_store: Res<DiagnosticsStore>) {
80+
if let (Some(render_meshes), Some(allocations)) = (
81+
diagnostic_store
82+
.get_measurement(
83+
&RenderAssetDiagnosticPlugin::<RenderMesh>::render_asset_diagnostic_path(),
84+
)
85+
.filter(|diag| diag.value > 0.),
86+
diagnostic_store
87+
.get_measurement(MeshAllocatorDiagnosticPlugin::allocations_diagnostic_path())
88+
.filter(|diag| diag.value > 0.),
89+
) {
90+
assert!(
91+
render_meshes.value < allocations.value * 10.,
92+
"Detected leak"
93+
);
94+
}
95+
}

0 commit comments

Comments
 (0)