surrealdb_core/sys/
mod.rs

1use futures::lock::Mutex;
2use std::sync::LazyLock;
3use sysinfo::Pid;
4use sysinfo::System;
5
6/// The current system environment which is used to
7/// periodically fetch and compute the system metrics.
8pub static ENVIRONMENT: LazyLock<Mutex<Environment>> =
9	LazyLock::new(|| Mutex::new(Environment::default()));
10
11/// The current system information which was acquired
12/// from the periodic environment process computation.
13pub static INFORMATION: LazyLock<Mutex<Information>> =
14	LazyLock::new(|| Mutex::new(Information::default()));
15
16pub async fn refresh() {
17	// Get the environment
18	let mut environment = ENVIRONMENT.lock().await;
19	environment.refresh();
20	// Get the system information cache
21	let mut information = INFORMATION.lock().await;
22	// Update the cached information metrics
23	information.cpu_usage = environment.cpu_usage();
24	(information.memory_allocated, information.threads) = crate::mem::ALLOC.current_usage();
25	information.memory_usage = environment.memory_usage();
26	information.load_average = environment.load_average();
27	information.physical_cores = environment.physical_cores();
28	information.available_parallelism = environment.available_parallelism();
29}
30
31/// Cached system utilisation metrics information
32#[derive(Default)]
33pub struct Information {
34	pub available_parallelism: usize,
35	pub cpu_usage: f32,
36	pub load_average: [f64; 3],
37	pub memory_allocated: usize,
38	pub threads: usize,
39	pub memory_usage: u64,
40	pub physical_cores: usize,
41}
42
43/// An environment for fetching system utilisation
44pub struct Environment {
45	sys: System,
46	pid: Pid,
47}
48
49impl Default for Environment {
50	fn default() -> Self {
51		Self {
52			sys: System::new_all(),
53			#[cfg(target_family = "wasm")]
54			pid: 0.into(),
55			#[cfg(not(target_family = "wasm"))]
56			pid: Pid::from(std::process::id() as usize),
57		}
58	}
59}
60
61impl Environment {
62	/// Returns the system load average value.
63	/// This function returns three numbers,
64	/// representing the last 1 minute, 5
65	/// minute, and 15 minute periods.
66	pub fn load_average(&self) -> [f64; 3] {
67		let load = System::load_average();
68		[load.one, load.five, load.fifteen]
69	}
70
71	/// Fetches the estimate of the available
72	/// parallelism of the hardware on which the
73	/// database is running. This number often
74	/// corresponds to the amount of CPUs, but
75	/// it may diverge in various cases.
76	pub fn physical_cores(&self) -> usize {
77		self.sys.physical_core_count().unwrap_or_default()
78	}
79
80	/// Fetches the estimate of the available
81	/// parallelism of the hardware on which the
82	/// database is running. This number often
83	/// corresponds to the amount of CPUs, but
84	/// it may diverge in various cases.
85	pub fn available_parallelism(&self) -> usize {
86		std::thread::available_parallelism().map_or_else(|_| num_cpus::get(), |m| m.get())
87	}
88
89	/// Returns the total CPU usage of the system
90	/// as a percentage. This may be greater than
91	/// 100% if running on a mult-core machine.
92	pub fn cpu_usage(&self) -> f32 {
93		if let Some(process) = self.sys.process(self.pid) {
94			process.cpu_usage()
95		} else {
96			0.0
97		}
98	}
99
100	/// Returns the total memory usage (in bytes)
101	/// of the system. This is the size of the
102	/// memory allocated, not including swap.
103	pub fn memory_usage(&self) -> u64 {
104		if let Some(process) = self.sys.process(self.pid) {
105			process.memory()
106		} else {
107			0
108		}
109	}
110
111	/// Refreshes the current process information
112	/// with memory and cpu usage details. This
113	/// ensures that we only fetch data we need.
114	pub fn refresh(&mut self) {
115		self.sys.refresh_processes_specifics(
116			sysinfo::ProcessesToUpdate::Some(&[self.pid]),
117			true,
118			sysinfo::ProcessRefreshKind::nothing().with_memory().with_cpu(),
119		);
120	}
121}