use std::sync::LazyLock;
use futures::lock::Mutex;
use sysinfo::{Pid, System};
#[cfg_attr(not(any(feature = "kv-rocksdb", feature = "kv-surrealkv")), allow(dead_code))]
pub(crate) static TOTAL_SYSTEM_MEMORY: LazyLock<u64> = LazyLock::new(|| {
let mut system = System::new();
system.refresh_memory();
let host_memory = system.total_memory();
if host_memory == 0 {
return 1024 * 1024 * 1024;
}
match system.cgroup_limits() {
Some(l) if l.total_memory > 0 => l.total_memory,
_ => host_memory,
}
});
pub static ENVIRONMENT: LazyLock<Mutex<Environment>> =
LazyLock::new(|| Mutex::new(Environment::default()));
pub static INFORMATION: LazyLock<Mutex<Information>> =
LazyLock::new(|| Mutex::new(Information::default()));
pub async fn refresh() {
let mut environment = ENVIRONMENT.lock().await;
environment.refresh();
let mut information = INFORMATION.lock().await;
information.cpu_usage = environment.cpu_usage();
information.memory_allocated = crate::mem::ALLOC.memory_allocated();
information.memory_usage = environment.memory_usage();
information.load_average = environment.load_average();
information.physical_cores = environment.physical_cores();
information.available_parallelism = environment.available_parallelism();
}
#[derive(Default)]
pub struct Information {
pub available_parallelism: usize,
pub cpu_usage: f32,
pub load_average: [f64; 3],
pub memory_allocated: usize,
pub memory_usage: u64,
pub physical_cores: usize,
}
pub struct Environment {
sys: System,
pid: Pid,
}
impl Default for Environment {
fn default() -> Self {
Self {
sys: System::new_all(),
#[cfg(target_family = "wasm")]
pid: 0.into(),
#[cfg(not(target_family = "wasm"))]
pid: Pid::from(std::process::id() as usize),
}
}
}
impl Environment {
pub fn load_average(&self) -> [f64; 3] {
let load = System::load_average();
[load.one, load.five, load.fifteen]
}
pub fn physical_cores(&self) -> usize {
num_cpus::get_physical()
}
pub fn available_parallelism(&self) -> usize {
std::thread::available_parallelism().map_or_else(|_| num_cpus::get(), |m| m.get())
}
pub fn cpu_usage(&self) -> f32 {
if let Some(process) = self.sys.process(self.pid) {
process.cpu_usage()
} else {
0.0
}
}
pub fn memory_usage(&self) -> u64 {
if let Some(process) = self.sys.process(self.pid) {
process.memory()
} else {
0
}
}
pub fn refresh(&mut self) {
self.sys.refresh_processes_specifics(
sysinfo::ProcessesToUpdate::Some(&[self.pid]),
true,
sysinfo::ProcessRefreshKind::nothing().with_memory().with_cpu(),
);
}
}