Skip to content

Commit 290d636

Browse files
l1npengtulIceSentry
andcommitted
add system information plugin and update relevant examples (bevyengine#5911)
# Objective Solve bevyengine#5464 ## Solution Adds a `SystemInformationDiagnosticsPlugin` to add diagnostics. Adds `Cargo.toml` flags to fix building on different platforms. --- ## Changelog Adds `sysinfo` crate to `bevy-diagnostics`. Changes in import order are due to clippy. Co-authored-by: l1npengtul <[email protected]> Co-authored-by: IceSentry <[email protected]>
1 parent b027d40 commit 290d636

File tree

3 files changed

+166
-55
lines changed

3 files changed

+166
-55
lines changed

crates/bevy_diagnostic/src/lib.rs

+5-55
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ mod diagnostic;
22
mod entity_count_diagnostics_plugin;
33
mod frame_time_diagnostics_plugin;
44
mod log_diagnostics_plugin;
5-
use bevy_log::info;
5+
mod system_information_diagnostics_plugin;
6+
7+
use bevy_app::prelude::*;
68
pub use diagnostic::*;
79
pub use entity_count_diagnostics_plugin::EntityCountDiagnosticsPlugin;
810
pub use frame_time_diagnostics_plugin::FrameTimeDiagnosticsPlugin;
911
pub use log_diagnostics_plugin::LogDiagnosticsPlugin;
10-
11-
use bevy_app::prelude::*;
12+
pub use system_information_diagnostics_plugin::SystemInformationDiagnosticsPlugin;
1213

1314
/// Adds core diagnostics resources to an App.
1415
#[derive(Default)]
@@ -17,61 +18,10 @@ pub struct DiagnosticsPlugin;
1718
impl Plugin for DiagnosticsPlugin {
1819
fn build(&self, app: &mut App) {
1920
app.init_resource::<Diagnostics>()
20-
.add_startup_system(log_system_info);
21+
.add_startup_system(system_information_diagnostics_plugin::internal::log_system_info);
2122
}
2223
}
2324

2425
/// The width which diagnostic names will be printed as
2526
/// Plugin names should not be longer than this value
2627
pub const MAX_DIAGNOSTIC_NAME_WIDTH: usize = 32;
27-
28-
#[derive(Debug)]
29-
// This is required because the Debug trait doesn't detect it's used when it's only used in a print :(
30-
#[allow(dead_code)]
31-
struct SystemInfo {
32-
os: String,
33-
kernel: String,
34-
cpu: String,
35-
core_count: String,
36-
memory: String,
37-
}
38-
39-
const BYTES_TO_GIB: f64 = 1.0 / 1024.0 / 1024.0 / 1024.0;
40-
41-
fn log_system_info() {
42-
// NOTE: sysinfo fails to compile when using bevy dynamic or on iOS and does nothing on wasm
43-
#[cfg(all(
44-
any(
45-
target_os = "linux",
46-
target_os = "windows",
47-
target_os = "android",
48-
target_os = "macos"
49-
),
50-
not(feature = "bevy_dynamic_plugin")
51-
))]
52-
{
53-
use sysinfo::{CpuExt, SystemExt};
54-
55-
let mut sys = sysinfo::System::new();
56-
sys.refresh_cpu();
57-
sys.refresh_memory();
58-
59-
let info = SystemInfo {
60-
os: sys
61-
.long_os_version()
62-
.unwrap_or_else(|| String::from("not available")),
63-
kernel: sys
64-
.kernel_version()
65-
.unwrap_or_else(|| String::from("not available")),
66-
cpu: sys.global_cpu_info().brand().trim().to_string(),
67-
core_count: sys
68-
.physical_core_count()
69-
.map(|x| x.to_string())
70-
.unwrap_or_else(|| String::from("not available")),
71-
// Convert from Bytes to GibiBytes since it's probably what people expect most of the time
72-
memory: format!("{:.1} GiB", sys.total_memory() as f64 * BYTES_TO_GIB),
73-
};
74-
75-
info!("{:?}", info);
76-
}
77-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
use crate::DiagnosticId;
2+
use bevy_app::{App, Plugin};
3+
4+
/// Adds a System Information Diagnostic, specifically `cpu_usage` (in %) and `mem_usage` (in %)
5+
///
6+
/// Supported targets:
7+
/// * linux,
8+
/// * windows,
9+
/// * android,
10+
/// * macos
11+
///
12+
/// NOT supported when using the `bevy/dynamic` feature even when using previously mentioned targets
13+
#[derive(Default)]
14+
pub struct SystemInformationDiagnosticsPlugin;
15+
impl Plugin for SystemInformationDiagnosticsPlugin {
16+
fn build(&self, app: &mut App) {
17+
app.add_startup_system(internal::setup_system)
18+
.add_system(internal::diagnostic_system);
19+
}
20+
}
21+
22+
impl SystemInformationDiagnosticsPlugin {
23+
pub const CPU_USAGE: DiagnosticId =
24+
DiagnosticId::from_u128(78494871623549551581510633532637320956);
25+
pub const MEM_USAGE: DiagnosticId =
26+
DiagnosticId::from_u128(42846254859293759601295317811892519825);
27+
}
28+
29+
// NOTE: sysinfo fails to compile when using bevy dynamic or on iOS and does nothing on wasm
30+
#[cfg(all(
31+
any(
32+
target_os = "linux",
33+
target_os = "windows",
34+
target_os = "android",
35+
target_os = "macos"
36+
),
37+
not(feature = "bevy_dynamic_plugin")
38+
))]
39+
pub mod internal {
40+
use bevy_ecs::{prelude::ResMut, system::Local};
41+
use bevy_log::info;
42+
use sysinfo::{CpuExt, System, SystemExt};
43+
44+
use crate::{Diagnostic, Diagnostics};
45+
46+
const BYTES_TO_GIB: f64 = 1.0 / 1024.0 / 1024.0 / 1024.0;
47+
48+
pub(crate) fn setup_system(mut diagnostics: ResMut<Diagnostics>) {
49+
diagnostics.add(
50+
Diagnostic::new(
51+
super::SystemInformationDiagnosticsPlugin::CPU_USAGE,
52+
"cpu_usage",
53+
20,
54+
)
55+
.with_suffix("%"),
56+
);
57+
diagnostics.add(
58+
Diagnostic::new(
59+
super::SystemInformationDiagnosticsPlugin::MEM_USAGE,
60+
"mem_usage",
61+
20,
62+
)
63+
.with_suffix("%"),
64+
);
65+
}
66+
67+
pub(crate) fn diagnostic_system(
68+
mut diagnostics: ResMut<Diagnostics>,
69+
mut sysinfo: Local<Option<System>>,
70+
) {
71+
if sysinfo.is_none() {
72+
*sysinfo = Some(System::new_all());
73+
}
74+
let Some(sys) = sysinfo.as_mut() else {
75+
return;
76+
};
77+
78+
sys.refresh_cpu();
79+
sys.refresh_memory();
80+
let current_cpu_usage = {
81+
let mut usage = 0.0;
82+
let cpus = sys.cpus();
83+
for cpu in cpus {
84+
usage += cpu.cpu_usage(); // NOTE: this returns a value from 0.0 to 100.0
85+
}
86+
// average
87+
usage / cpus.len() as f32
88+
};
89+
// `memory()` fns return a value in bytes
90+
let total_mem = sys.total_memory() as f64 / BYTES_TO_GIB;
91+
let used_mem = sys.used_memory() as f64 / BYTES_TO_GIB;
92+
let current_used_mem = used_mem / total_mem * 100.0;
93+
94+
diagnostics.add_measurement(super::SystemInformationDiagnosticsPlugin::CPU_USAGE, || {
95+
current_cpu_usage as f64
96+
});
97+
diagnostics.add_measurement(super::SystemInformationDiagnosticsPlugin::MEM_USAGE, || {
98+
current_used_mem
99+
});
100+
}
101+
102+
#[derive(Debug)]
103+
// This is required because the Debug trait doesn't detect it's used when it's only used in a print :(
104+
#[allow(dead_code)]
105+
struct SystemInfo {
106+
os: String,
107+
kernel: String,
108+
cpu: String,
109+
core_count: String,
110+
memory: String,
111+
}
112+
113+
pub(crate) fn log_system_info() {
114+
let mut sys = sysinfo::System::new();
115+
sys.refresh_cpu();
116+
sys.refresh_memory();
117+
118+
let info = SystemInfo {
119+
os: sys
120+
.long_os_version()
121+
.unwrap_or_else(|| String::from("not available")),
122+
kernel: sys
123+
.kernel_version()
124+
.unwrap_or_else(|| String::from("not available")),
125+
cpu: sys.global_cpu_info().brand().trim().to_string(),
126+
core_count: sys
127+
.physical_core_count()
128+
.map(|x| x.to_string())
129+
.unwrap_or_else(|| String::from("not available")),
130+
// Convert from Bytes to GibiBytes since it's probably what people expect most of the time
131+
memory: format!("{:.1} GiB", sys.total_memory() as f64 * BYTES_TO_GIB),
132+
};
133+
134+
info!("{:?}", info);
135+
}
136+
}
137+
138+
#[cfg(not(all(
139+
any(
140+
target_os = "linux",
141+
target_os = "windows",
142+
target_os = "android",
143+
target_os = "macos"
144+
),
145+
not(feature = "bevy_dynamic_plugin")
146+
)))]
147+
pub mod internal {
148+
pub(crate) fn setup_system() {
149+
bevy_log::warn!("This platform and/or configuration is not supported!");
150+
}
151+
152+
pub(crate) fn diagnostic_system() {
153+
// no-op
154+
}
155+
156+
pub(crate) fn log_system_info() {
157+
// no-op
158+
}
159+
}

examples/diagnostics/log_diagnostics.rs

+2
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@ fn main() {
1717
// .add_plugin(bevy::diagnostic::EntityCountDiagnosticsPlugin::default())
1818
// Uncomment this to add an asset count diagnostics:
1919
// .add_plugin(bevy::asset::diagnostic::AssetCountDiagnosticsPlugin::<Texture>::default())
20+
// Uncomment this to add system info diagnostics:
21+
// .add_plugin(bevy::diagnostic::SystemInformationDiagnosticsPlugin::default())
2022
.run();
2123
}

0 commit comments

Comments
 (0)