diff --git a/Plugin/unraid/include/media.php b/Plugin/unraid/include/media.php index 3475e92..c73986a 100644 --- a/Plugin/unraid/include/media.php +++ b/Plugin/unraid/include/media.php @@ -269,10 +269,26 @@ function vv_media_sessions(): array { // paid per page load — the background writer refreshes it every minute, so the CPU figure is at // most a minute stale, which is honest for a card rather than a live graph. Monitor is where live // belongs. +// Logical CPUs, which is what `docker stats` divides its CPU figure by — and therefore what has to +// be divided back out to get a share of the machine. +// +// Logical, not physical. This host reports 16 physical cores and 32 threads; docker's percentage is +// summed across all 32, so dividing by 16 would double every reading. The watchdog's own `cores` +// field is the physical 16 because it is comparing load averages, which is a different question — +// borrowing it here would have looked reasonable and been wrong by exactly a factor of two. +function vv_media_cpu_count(): int { + static $n = null; + if ($n !== null) return $n; + $n = (int)trim((string)@shell_exec('nproc 2>/dev/null')); + if ($n < 1) $n = max(1, (int)@substr_count((string)@file_get_contents('/proc/cpuinfo'), 'processor')); + return $n; +} + function vv_media_container_stats(array $names): array { $names = array_values(array_filter($names)); if (!$names) return []; + $cpus = vv_media_cpu_count(); $out = []; $args = implode(' ', array_map('escapeshellarg', $names)); $fmt = '{{.Name}}|{{.CPUPerc}}|{{.MemUsage}}|{{.MemPerc}}'; @@ -281,8 +297,16 @@ function vv_media_container_stats(array $names): array { $p = explode('|', $line); if (count($p) < 4) continue; [$mUsed, $mLimit] = array_pad(array_map('trim', explode('/', $p[2])), 2, ''); + $raw = (float)rtrim($p[1], '%'); $out[$p[0]] = [ - 'cpu_pct' => (float)rtrim($p[1], '%'), + // Share of the whole machine, so this card and Unraid's own Docker page report the + // same container as the same number. docker's raw figure is per-core-summed: 227% is + // 2.3 cores busy, which reads as an emergency on a card and is 7% of a 32-thread host. + // Kept alongside rather than discarded — "2.3 cores" is the useful form once you know + // it is not a percentage of anything. + 'cpu_pct' => round($raw / max(1, $cpus), 2), + 'cpu_raw' => $raw, + 'cpu_cores' => round($raw / 100, 2), 'mem_used' => $mUsed, 'mem_limit' => $mLimit, 'mem_pct' => (float)rtrim($p[3], '%'), diff --git a/Plugin/unraid/pages/arrs.php b/Plugin/unraid/pages/arrs.php index 6fdd29d..a7467c5 100644 --- a/Plugin/unraid/pages/arrs.php +++ b/Plugin/unraid/pages/arrs.php @@ -450,10 +450,12 @@ function _mediaServersSection(nodes) { const cards = shown.map(s => { const up = !!s.online; const dot = !up ? '#c62828' : s.pending_restart || s.update_available ? '#ffb74d' : '#4caf50'; - // Colour the CPU against cores, not against 100%: these are containers on a 16-core host, so - // 145% is busy rather than broken, and 1500% would be the number that matters. + // cpu_pct is a share of the whole machine, matching Unraid's Docker page. Thresholds are set + // against that: a single container taking a quarter of the host is worth noticing, half is + // worth alarming about. The earlier version coloured docker's raw per-core-summed figure and + // called 145% alarming when it was 4.5% of a 32-thread machine. const cpu = s.cpu_pct; - const cpuCol = cpu == null ? '#555' : cpu > 400 ? '#ef5350' : cpu > 150 ? '#ffb74d' : '#888'; + const cpuCol = cpu == null ? '#555' : cpu > 50 ? '#ef5350' : cpu > 25 ? '#ffb74d' : '#888'; const flags = []; if (s.update_available) flags.push(['update available', '#ffb74d']); @@ -477,7 +479,8 @@ function _mediaServersSection(nodes) {