From fe919ba0115fe9a9068c3f934978e4a10e2723ac Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Wed, 19 Mar 2025 08:33:38 +0200 Subject: [PATCH 1/6] Precompute paths in CgroupV2 --- src/stats/cgroup_v2/mod.rs | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/stats/cgroup_v2/mod.rs b/src/stats/cgroup_v2/mod.rs index 2f05302..351def4 100644 --- a/src/stats/cgroup_v2/mod.rs +++ b/src/stats/cgroup_v2/mod.rs @@ -46,47 +46,39 @@ impl SystemStatsSource for CgroupV2Source

{ } pub struct CgroupV2FilesystemReader { - cgroup_v2_path: PathBuf, + cpu_max_path: PathBuf, + cpu_stat_path: PathBuf, + mem_current_path: PathBuf, + mem_max_path: PathBuf, } impl CgroupV2FilesystemReader { fn new(cgroup_v2_path: PathBuf) -> Self { - Self { cgroup_v2_path } - } - - fn cpu_max_path(&self) -> PathBuf { - self.cgroup_v2_path.join("cpu.max") - } - - fn cpu_stat_path(&self) -> PathBuf { - self.cgroup_v2_path.join("cpu.stat") - } - - fn mem_current_path(&self) -> PathBuf { - self.cgroup_v2_path.join("memory.current") - } - - fn mem_max_path(&self) -> PathBuf { - self.cgroup_v2_path.join("memory.max") + Self { + cpu_max_path: cgroup_v2_path.join("cpu.max"), + cpu_stat_path: cgroup_v2_path.join("cpu.stat"), + mem_current_path: cgroup_v2_path.join("memory.current"), + mem_max_path: cgroup_v2_path.join("memory.max"), + } } } impl CgroupV2Provider for CgroupV2FilesystemReader { fn get_cgroup_v2_cpu_stat(&self) -> io::Result> { - let file = File::open(self.cpu_stat_path())?; + let file = File::open(&self.cpu_stat_path)?; BufReader::new(file).lines().collect() } fn get_cgroup_v2_cpu_max(&self) -> io::Result { - read_first_line(self.cpu_max_path()) + read_first_line(&self.cpu_max_path) } fn get_cgroup_v2_memory_current(&self) -> io::Result { - read_first_line(self.mem_current_path()) + read_first_line(&self.mem_current_path) } fn get_cgroup_v2_memory_max(&self) -> io::Result { - read_first_line(self.mem_max_path()) + read_first_line(&self.mem_max_path) } } From a38c7fa5fca13502f4c60e45d5f8e13d05ead6f2 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Wed, 19 Mar 2025 08:35:24 +0200 Subject: [PATCH 2/6] Add read_all_lines --- src/stats/cgroup_v1/mod.rs | 9 +++------ src/stats/cgroup_v2/mod.rs | 8 +++----- src/stats/proc/mod.rs | 10 ++++------ src/utils.rs | 6 ++++++ 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/stats/cgroup_v1/mod.rs b/src/stats/cgroup_v1/mod.rs index 2e85213..75427b4 100644 --- a/src/stats/cgroup_v1/mod.rs +++ b/src/stats/cgroup_v1/mod.rs @@ -3,9 +3,8 @@ mod cpu_usage; mod memory_current; mod memory_max; mod num_cpus; -use crate::utils::read_first_line; -use std::fs::File; -use std::io::{self, BufRead, BufReader}; +use crate::utils::{read_all_lines, read_first_line}; +use std::io::{self}; use std::path::PathBuf; #[cfg(test)] @@ -232,8 +231,6 @@ impl CgroupV1Provider for CgroupV1FilesystemReader { "memory.stat file not found", )); }; - - let file = File::open(file_path)?; - BufReader::new(file).lines().collect() + read_all_lines(file_path) } } diff --git a/src/stats/cgroup_v2/mod.rs b/src/stats/cgroup_v2/mod.rs index 351def4..b7ff35a 100644 --- a/src/stats/cgroup_v2/mod.rs +++ b/src/stats/cgroup_v2/mod.rs @@ -3,9 +3,8 @@ mod cpu_usage; mod memory_current; mod memory_max; mod num_cpus; -use crate::utils::read_first_line; -use std::fs::File; -use std::io::{self, BufRead, BufReader}; +use crate::utils::{read_all_lines, read_first_line}; +use std::io::{self}; use std::path::PathBuf; #[cfg(test)] @@ -65,8 +64,7 @@ impl CgroupV2FilesystemReader { impl CgroupV2Provider for CgroupV2FilesystemReader { fn get_cgroup_v2_cpu_stat(&self) -> io::Result> { - let file = File::open(&self.cpu_stat_path)?; - BufReader::new(file).lines().collect() + read_all_lines(&self.cpu_stat_path) } fn get_cgroup_v2_cpu_max(&self) -> io::Result { diff --git a/src/stats/proc/mod.rs b/src/stats/proc/mod.rs index c711c26..2f2054e 100644 --- a/src/stats/proc/mod.rs +++ b/src/stats/proc/mod.rs @@ -3,10 +3,10 @@ mod memory; mod num_cpus; use crate::stats::{CpuUsageValue, SystemStatsSource}; -use std::fs::File; -use std::io::{self, BufRead, BufReader}; +use std::io::{self}; use std::path::PathBuf; +use crate::utils::read_all_lines; #[cfg(test)] use mockall::automock; use tracing::debug; @@ -71,13 +71,11 @@ impl ProcFilesystemReader { impl ProcProvider for ProcFilesystemReader { fn get_proc_stat(&self) -> io::Result> { - let file = File::open(self.proc_stat_path())?; - BufReader::new(file).lines().collect() + read_all_lines(self.proc_stat_path()) } fn get_proc_meminfo(&self) -> io::Result> { - let file = File::open(self.proc_meminfo_path())?; - BufReader::new(file).lines().collect() + read_all_lines(self.proc_meminfo_path()) } } diff --git a/src/utils.rs b/src/utils.rs index e8ee6b0..23c8c3b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -9,3 +9,9 @@ pub fn read_first_line>(path: P) -> io::Result { reader.read_line(&mut line)?; Ok(line) } + +pub fn read_all_lines>(path: P) -> io::Result> { + let file = File::open(path)?; + let reader = BufReader::new(file); + reader.lines().collect() +} From c0641ee0286a54db9e48afcc506c24653816aa93 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Wed, 19 Mar 2025 08:39:04 +0200 Subject: [PATCH 3/6] Clone less in cgroup_v1 --- .github/workflows/ci.yml | 1 + src/stats/cgroup_v1/mod.rs | 126 ++++++++----------------------------- src/utils.rs | 10 ++- 3 files changed, 37 insertions(+), 100 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30724a9..f9c1663 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,6 +54,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: components: rustfmt, clippy + - uses: Swatinem/rust-cache@v2 - run: cargo fmt --all -- --check - run: cargo clippy --no-deps diff --git a/src/stats/cgroup_v1/mod.rs b/src/stats/cgroup_v1/mod.rs index 75427b4..28c6c33 100644 --- a/src/stats/cgroup_v1/mod.rs +++ b/src/stats/cgroup_v1/mod.rs @@ -3,12 +3,11 @@ mod cpu_usage; mod memory_current; mod memory_max; mod num_cpus; -use crate::utils::{read_all_lines, read_first_line}; -use std::io::{self}; -use std::path::PathBuf; - +use crate::utils::{get_path_or_croak, read_all_lines, read_first_line}; #[cfg(test)] use mockall::automock; +use std::io::{self}; +use std::path::PathBuf; #[derive(Default, Clone)] pub struct CgroupV1MountPoints { @@ -64,30 +63,6 @@ impl CgroupV1MountPoints { self.memory_stat_path = memory.as_ref().map(|pb| pb.join("memory.stat")); self.memory = memory; } - - pub fn cpu_quota_path(&self) -> Option { - self.cpu_quota_path.clone() - } - - pub fn cpu_period_path(&self) -> Option { - self.cpu_period_path.clone() - } - - pub fn cpu_usage_path(&self) -> Option { - self.cpu_usage_path.clone() - } - - pub fn memory_usage_path(&self) -> Option { - self.memory_usage_path.clone() - } - - pub fn memory_limit_path(&self) -> Option { - self.memory_limit_path.clone() - } - - pub fn memory_stat_path(&self) -> Option { - self.memory_stat_path.clone() - } } pub struct CgroupV1Source { @@ -132,30 +107,6 @@ impl CgroupV1FilesystemReader { fn new(mount_points: CgroupV1MountPoints) -> Self { Self { mount_points } } - - fn cpu_quota_path(&self) -> Option { - self.mount_points.cpu_quota_path() - } - - fn cpu_period_path(&self) -> Option { - self.mount_points.cpu_period_path() - } - - fn cpu_usage(&self) -> Option { - self.mount_points.cpu_usage_path() - } - - fn memory_usage_path(&self) -> Option { - self.mount_points.memory_usage_path() - } - - fn memory_limit_path(&self) -> Option { - self.mount_points.memory_limit_path() - } - - fn memory_stat_path(&self) -> Option { - self.mount_points.memory_stat_path() - } } #[cfg_attr(test, automock)] @@ -170,67 +121,44 @@ pub trait CgroupV1Provider { impl CgroupV1Provider for CgroupV1FilesystemReader { fn get_cgroup_v1_cpu_cfs_quota(&self) -> io::Result { - let Some(file_path) = self.cpu_quota_path() else { - return Err(io::Error::new( - io::ErrorKind::NotFound, - "cpu.cfs_quota_us file not found", - )); - }; - - read_first_line(file_path) + read_first_line(get_path_or_croak( + &self.mount_points.cpu_quota_path, + "cpu.cfs_quota_us", + )?) } fn get_cgroup_v1_cpu_cfs_period(&self) -> io::Result { - let Some(file_path) = self.cpu_period_path() else { - return Err(io::Error::new( - io::ErrorKind::NotFound, - "cpu.cfs_period_us file not found", - )); - }; - - read_first_line(file_path) + read_first_line(get_path_or_croak( + &self.mount_points.cpu_period_path, + "cpu.cfs_period_us", + )?) } fn get_cgroup_v1_cpuacct_usage(&self) -> io::Result { - let Some(file_path) = self.cpu_usage() else { - return Err(io::Error::new( - io::ErrorKind::NotFound, - "cpuacct.usage file not found", - )); - }; - - read_first_line(file_path) + read_first_line(get_path_or_croak( + &self.mount_points.cpu_usage_path, + "cpuacct.usage", + )?) } fn get_cgroup_v1_memory_usage_in_bytes(&self) -> io::Result { - let Some(file_path) = self.memory_usage_path() else { - return Err(io::Error::new( - io::ErrorKind::NotFound, - "memory.usage_in_bytes file not found", - )); - }; - - read_first_line(file_path) + read_first_line(get_path_or_croak( + &self.mount_points.memory_usage_path, + "memory.usage_in_bytes", + )?) } fn get_cgroup_v1_memory_limit_in_bytes(&self) -> io::Result { - let Some(file_path) = self.memory_limit_path() else { - return Err(io::Error::new( - io::ErrorKind::NotFound, - "memory.limit_in_bytes file not found", - )); - }; - - read_first_line(file_path) + read_first_line(get_path_or_croak( + &self.mount_points.memory_limit_path, + "memory.limit_in_bytes", + )?) } fn get_cgroup_v1_memory_stat(&self) -> io::Result> { - let Some(file_path) = self.memory_stat_path() else { - return Err(io::Error::new( - io::ErrorKind::NotFound, - "memory.stat file not found", - )); - }; - read_all_lines(file_path) + read_all_lines(get_path_or_croak( + &self.mount_points.memory_stat_path, + "memory.stat", + )?) } } diff --git a/src/utils.rs b/src/utils.rs index 23c8c3b..5e1148c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,6 @@ use std::fs::File; use std::io::{self, BufRead, BufReader}; -use std::path::Path; +use std::path::{Path, PathBuf}; pub fn read_first_line>(path: P) -> io::Result { let file = File::open(path)?; @@ -15,3 +15,11 @@ pub fn read_all_lines>(path: P) -> io::Result> { let reader = BufReader::new(file); reader.lines().collect() } + +pub fn get_path_or_croak<'a>( + path: &'a Option, + thing: &'static str, +) -> io::Result<&'a PathBuf> { + path.as_ref() + .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, format!("{thing} file not found"))) +} From 7f0ad2389dda9ff39b2cd19d82a2b995d4423a5e Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Wed, 19 Mar 2025 08:57:18 +0200 Subject: [PATCH 4/6] Dynify main loop --- src/lib.rs | 82 +++++++++++++++++++++++++----------------- src/stats/mod.rs | 92 ++---------------------------------------------- 2 files changed, 53 insertions(+), 121 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 22a9f9c..d9d9408 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,42 +3,34 @@ pub mod stats; pub mod store; pub mod utils; +use crate::stats::cgroup_v1::CgroupV1Source; +use crate::stats::cgroup_v2::CgroupV2Source; +use crate::stats::proc::ProcSource; use crate::stats::{ - CpuUsageValue, detect_cgroup_version, get_cgroup_v1_mount_points, get_cgroup_v2_mount_point, + CpuUsageValue, SystemStatsSource, detect_cgroup_version, get_cgroup_v1_mount_points, + get_cgroup_v2_mount_point, }; use crate::store::StatsEntry; +use std::path::PathBuf; use std::thread; use tracing::{debug, error}; pub fn run_acolyte() { let stat_interval = env::get_stat_interval(); - let cgroup_version = detect_cgroup_version("/proc/self/cgroup").ok(); - let v2_mount_point = cgroup_version - .as_ref() - .filter(|v| v.has_v2()) - .and_then(|_| get_cgroup_v2_mount_point("/proc/mounts").ok()); - let v1_mount_points = cgroup_version - .as_ref() - .filter(|v| v.has_v1()) - .and_then(|_| get_cgroup_v1_mount_points("/proc/mounts").ok()); + + let sources = get_sources(); loop { let mut stats_entry = StatsEntry::new(); - let maybe_num_cpus = stats::get_num_cpus( - cgroup_version.clone(), - v2_mount_point.clone(), - v1_mount_points.clone(), - ); - if let Some(num_cpus) = maybe_num_cpus { + if let Some(num_cpus) = sources.iter().find_map(|source| source.get_num_cpus().ok()) { stats_entry.num_cpus = Some(num_cpus); } - if let Some(cpu_usage) = stats::get_cpu_usage( - cgroup_version.clone(), - v2_mount_point.clone(), - v1_mount_points.clone(), - ) { + if let Some(cpu_usage) = sources + .iter() + .find_map(|source| source.get_cpu_usage().ok()) + { // scale the cpu usage by the number of cpus // so that 100% cpu usage on a 4 core machine is 4.0 etc. let normalized_cpu_usage = match cpu_usage { @@ -47,7 +39,7 @@ pub fn run_acolyte() { CpuUsageValue::FromProc(proc_usage) => { // for the `procfs` values to report the number in the right format, // we MUST know the number of cpus or the number will be misleading - if let Some(num_cpus) = maybe_num_cpus { + if let Some(num_cpus) = stats_entry.num_cpus { Some(proc_usage * num_cpus) } else { debug!("Failed to get number of CPUs, skipping procfs CPU usage"); @@ -58,19 +50,17 @@ pub fn run_acolyte() { stats_entry.cpu_usage = normalized_cpu_usage; } - if let Some(mem_usage_kb) = stats::get_memory_usage_kb( - cgroup_version.clone(), - v2_mount_point.clone(), - v1_mount_points.clone(), - ) { + if let Some(mem_usage_kb) = sources + .iter() + .find_map(|source| source.get_memory_usage_kb().ok()) + { stats_entry.memory_usage_kb = Some(mem_usage_kb); } - if let Some(mem_total_kb) = stats::get_memory_total_kb( - cgroup_version.clone(), - v2_mount_point.clone(), - v1_mount_points.clone(), - ) { + if let Some(mem_total_kb) = sources + .iter() + .find_map(|source| source.get_memory_total_kb().ok()) + { stats_entry.memory_total_kb = Some(mem_total_kb); } @@ -89,3 +79,31 @@ pub fn run_acolyte() { thread::sleep(stat_interval); } } + +fn get_sources() -> Vec> { + let mut sources: Vec> = vec![]; + let cgroup_version = detect_cgroup_version("/proc/self/cgroup").ok(); + + if let Some(v2_mount_point) = cgroup_version + .as_ref() + .filter(|v| v.has_v2()) + .and_then(|_| get_cgroup_v2_mount_point("/proc/mounts").ok()) + { + sources.push(Box::new(CgroupV2Source::with_filesystem_reader_at( + v2_mount_point, + ))); + } + if let Some(v1_mount_points) = cgroup_version + .as_ref() + .filter(|v| v.has_v1()) + .and_then(|_| get_cgroup_v1_mount_points("/proc/mounts").ok()) + { + sources.push(Box::new(CgroupV1Source::with_filesystem_reader_at( + v1_mount_points, + ))); + } + sources.push(Box::new(ProcSource::with_filesystem_reader_at( + PathBuf::from("/proc"), + ))); + sources +} diff --git a/src/stats/mod.rs b/src/stats/mod.rs index c11618c..d21c16c 100644 --- a/src/stats/mod.rs +++ b/src/stats/mod.rs @@ -1,17 +1,14 @@ -mod cgroup_v1; -mod cgroup_v2; +pub(crate) mod cgroup_v1; +pub(crate) mod cgroup_v2; mod nvidia_smi; mod paths; -mod proc; +pub(crate) mod proc; -use crate::stats::cgroup_v1::CgroupV1MountPoints; pub use crate::stats::paths::{ detect_cgroup_version, get_cgroup_v1_mount_points, get_cgroup_v2_mount_point, }; use nvidia_smi::NvidiaSmiExecutor; -use proc::ProcSource; use std::io; -use std::path::PathBuf; // TODO: see if we could make this a bit simpler or give these a better name pub enum CpuUsageValue { @@ -49,58 +46,6 @@ impl CgroupVersion { } } -pub fn get_num_cpus( - cgroup_version: Option, - cgroup_v2_mount_point: Option, - cgroup_v1_mount_points: Option, -) -> Option { - get_resource_with_fallback( - cgroup_version, - cgroup_v2_mount_point, - cgroup_v1_mount_points, - |source| source.get_num_cpus(), - ) -} - -pub fn get_cpu_usage( - cgroup_version: Option, - cgroup_v2_mount_point: Option, - cgroup_v1_mount_points: Option, -) -> Option { - get_resource_with_fallback( - cgroup_version, - cgroup_v2_mount_point, - cgroup_v1_mount_points, - |source| source.get_cpu_usage(), - ) -} - -pub fn get_memory_usage_kb( - cgroup_version: Option, - cgroup_v2_mount_point: Option, - cgroup_v1_mount_points: Option, -) -> Option { - get_resource_with_fallback( - cgroup_version, - cgroup_v2_mount_point, - cgroup_v1_mount_points, - |source| source.get_memory_usage_kb(), - ) -} - -pub fn get_memory_total_kb( - cgroup_version: Option, - cgroup_v2_mount_point: Option, - cgroup_v1_mount_points: Option, -) -> Option { - get_resource_with_fallback( - cgroup_version, - cgroup_v2_mount_point, - cgroup_v1_mount_points, - |source| source.get_memory_total_kb(), - ) -} - pub fn get_gpu_stats() -> Option { // we only support NVIDIA GPUs for now so no need to check for other sources let executor = NvidiaSmiExecutor::new(); @@ -113,34 +58,3 @@ pub trait SystemStatsSource { fn get_memory_usage_kb(&self) -> io::Result; fn get_memory_total_kb(&self) -> io::Result; } - -fn get_resource_with_fallback( - cgroup_version: Option, - cgroup_v2_mount_point: Option, - cgroup_v1_mount_points: Option, - stat_getter: F, -) -> Option -where - F: Fn(&dyn SystemStatsSource) -> io::Result, -{ - if cgroup_version.as_ref().filter(|v| v.has_v2()).is_some() { - if let Some(v2_mount_point) = cgroup_v2_mount_point { - let source = cgroup_v2::CgroupV2Source::with_filesystem_reader_at(v2_mount_point); - if let Ok(result) = stat_getter(&source) { - return Some(result); - } - } - } - - if cgroup_version.as_ref().filter(|v| v.has_v1()).is_some() { - if let Some(v1_mount_points) = cgroup_v1_mount_points { - let source = cgroup_v1::CgroupV1Source::with_filesystem_reader_at(v1_mount_points); - if let Ok(result) = stat_getter(&source) { - return Some(result); - } - } - } - - let source = ProcSource::with_filesystem_reader_at(PathBuf::from("/proc")); - stat_getter(&source).ok() -} From 88034737e6486ca1607f76bbf935a288956409ba Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Wed, 19 Mar 2025 08:59:04 +0200 Subject: [PATCH 5/6] Move CpuUsageValue.normalize --- src/lib.rs | 21 ++------------------- src/stats/mod.rs | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d9d9408..9716584 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,7 @@ use crate::stats::cgroup_v1::CgroupV1Source; use crate::stats::cgroup_v2::CgroupV2Source; use crate::stats::proc::ProcSource; use crate::stats::{ - CpuUsageValue, SystemStatsSource, detect_cgroup_version, get_cgroup_v1_mount_points, - get_cgroup_v2_mount_point, + SystemStatsSource, detect_cgroup_version, get_cgroup_v1_mount_points, get_cgroup_v2_mount_point, }; use crate::store::StatsEntry; use std::path::PathBuf; @@ -31,23 +30,7 @@ pub fn run_acolyte() { .iter() .find_map(|source| source.get_cpu_usage().ok()) { - // scale the cpu usage by the number of cpus - // so that 100% cpu usage on a 4 core machine is 4.0 etc. - let normalized_cpu_usage = match cpu_usage { - CpuUsageValue::FromCgroupV2(cgroup_usage) => Some(cgroup_usage), - CpuUsageValue::FromCgroupV1(cgroup_usage) => Some(cgroup_usage), - CpuUsageValue::FromProc(proc_usage) => { - // for the `procfs` values to report the number in the right format, - // we MUST know the number of cpus or the number will be misleading - if let Some(num_cpus) = stats_entry.num_cpus { - Some(proc_usage * num_cpus) - } else { - debug!("Failed to get number of CPUs, skipping procfs CPU usage"); - None - } - } - }; - stats_entry.cpu_usage = normalized_cpu_usage; + stats_entry.cpu_usage = cpu_usage.normalize(stats_entry.num_cpus); } if let Some(mem_usage_kb) = sources diff --git a/src/stats/mod.rs b/src/stats/mod.rs index d21c16c..83cd803 100644 --- a/src/stats/mod.rs +++ b/src/stats/mod.rs @@ -9,6 +9,7 @@ pub use crate::stats::paths::{ }; use nvidia_smi::NvidiaSmiExecutor; use std::io; +use tracing::debug; // TODO: see if we could make this a bit simpler or give these a better name pub enum CpuUsageValue { @@ -17,6 +18,27 @@ pub enum CpuUsageValue { FromProc(f64), // fractional CPU usage i.e., 0.75 for 75% of all CPUs busy } +impl CpuUsageValue { + // scale the cpu usage by the number of cpus + // so that 100% cpu usage on a 4 core machine is 4.0 etc. + pub fn normalize(self, num_cpus: Option) -> Option { + match self { + CpuUsageValue::FromCgroupV2(cgroup_usage) => Some(cgroup_usage), + CpuUsageValue::FromCgroupV1(cgroup_usage) => Some(cgroup_usage), + CpuUsageValue::FromProc(proc_usage) => { + // for the `procfs` values to report the number in the right format, + // we MUST know the number of cpus or the number will be misleading + if let Some(num_cpus) = num_cpus { + Some(proc_usage * num_cpus) + } else { + debug!("Failed to get number of CPUs, skipping procfs CPU usage"); + None + } + } + } + } +} + pub struct GpuStats { pub num_gpus: u32, // N = number of GPUs pub gpu_usage: f64, // normalized usage across all GPUs (0.0 - N.0) From 3775d5c3bbe999964cb9069a2f8135939f048d52 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Wed, 19 Mar 2025 09:20:17 +0200 Subject: [PATCH 6/6] Early-out in detect_cgroup_version --- src/stats/paths.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/stats/paths.rs b/src/stats/paths.rs index e86588d..4a339b3 100644 --- a/src/stats/paths.rs +++ b/src/stats/paths.rs @@ -96,6 +96,10 @@ pub fn detect_cgroup_version>(self_cgroup_path: P) -> io::Result< } else { has_v1_entries = true; } + if has_v1_entries && has_v2_entries { + // Got both, can quit early. + break; + } } if has_v1_entries && has_v2_entries {