Report container CPU as a share of the machine, matching Unraid's Docker page

docker stats sums CPU across every logical processor, so Jellyfin's "227%" is
2.3 threads busy — 7% of a 32-thread host, which is what Unraid shows and what
the operator was reading. The card was printing the raw figure and colouring it
against thresholds meant for a percentage, so ordinary background work looked
like an emergency; I twice flagged Jellyfin as pegged on that basis and was
wrong both times. Divides by nproc, not the watchdog's `cores` — that field is
the physical 16 because it compares load averages, and borrowing it here would
have looked reasonable and doubled every reading.
This commit is contained in:
Gmer4Lfe
2026-08-14 19:39:14 -04:00
parent 04a0dcb39a
commit dbc0c8c6d2
2 changed files with 32 additions and 5 deletions
+25 -1
View File
@@ -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], '%'),