stats(p3): normalise cpu% against host CPU count, not process affinity
Per review: available_parallelism() respects the hive-core process's CPU affinity, so if it's ever affinity-pinned the denominator would under-count and inflate cpu_pct. Read the online host CPUs from /sys/devices/system/cpu/online instead (fall back to the process count, then 1) so the 'percent of total host CPU' definition holds regardless.
This commit is contained in:
parent
03ea6d1bda
commit
dbb9f2a787
1 changed files with 32 additions and 1 deletions
|
|
@ -91,6 +91,37 @@ fn read_usage_usec(dir: &std::path::Path) -> Option<u64> {
|
|||
None
|
||||
}
|
||||
|
||||
/// Total online host CPUs, for normalising CPU% to "% of total host".
|
||||
/// Reads `/sys/devices/system/cpu/online` (a comma-separated list of
|
||||
/// ranges, e.g. `0-19`) rather than `available_parallelism()`, which
|
||||
/// reflects the hive-core process's CPU affinity — if hive-core is ever
|
||||
/// affinity-pinned to a subset, that would under-count the denominator
|
||||
/// and inflate the percentage. Falls back to the process count, then 1.
|
||||
fn host_nproc() -> usize {
|
||||
fn from_sysfs() -> Option<usize> {
|
||||
let s = std::fs::read_to_string("/sys/devices/system/cpu/online").ok()?;
|
||||
let mut count = 0usize;
|
||||
for part in s.trim().split(',') {
|
||||
let part = part.trim();
|
||||
if part.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if let Some((a, b)) = part.split_once('-') {
|
||||
let a: usize = a.trim().parse().ok()?;
|
||||
let b: usize = b.trim().parse().ok()?;
|
||||
count += b.saturating_sub(a) + 1;
|
||||
} else {
|
||||
part.parse::<usize>().ok()?;
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
(count > 0).then_some(count)
|
||||
}
|
||||
from_sysfs()
|
||||
.or_else(|| std::thread::available_parallelism().ok().map(usize::from))
|
||||
.unwrap_or(1)
|
||||
}
|
||||
|
||||
/// Sample CPU + memory for every running agent container. Best-effort:
|
||||
/// agents whose scope dir is absent (not running) or unreadable are
|
||||
/// skipped, never fatal. Sorted by name for a stable display order.
|
||||
|
|
@ -111,7 +142,7 @@ pub async fn gather() -> Vec<ContainerResource> {
|
|||
sleep(CPU_SAMPLE).await;
|
||||
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
let nproc = std::thread::available_parallelism().map_or(1.0, |n| n.get() as f64);
|
||||
let nproc = host_nproc() as f64;
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
let interval_usec = CPU_SAMPLE.as_micros() as f64;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue