Skip to content

Commit b835950

Browse files
authored
Merge pull request #2407 from SimonFair/CPU-Packages
Feat:Add power, temps and Split physical CPUS
2 parents b736f9c + 117a494 commit b835950

File tree

3 files changed

+156
-17
lines changed

3 files changed

+156
-17
lines changed

emhttp/plugins/dynamix/DashStats.page

Lines changed: 117 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ foreach ($devs as $disk) {
9494
}
9595

9696
$array_percent = number_format(100*$array_used/($array_size ?: 1),1,$dot,'');
97-
exec('cat /sys/devices/system/cpu/*/topology/thread_siblings_list|sort -nu', $cpus);
97+
$cpus=get_cpu_packages();
9898
$wg_up = $wireguard ? exec("wg show interfaces") : '';
9999
$wg_up = $wg_up ? explode(' ',$wg_up) : [];
100100
$up = count($wg_up);
@@ -351,8 +351,13 @@ switch ($themeHelper->getThemeName()) { // $themeHelper set in DefaultPageLayout
351351
<td>
352352
<span class='flex flex-row flex-wrap items-center gap-4'>
353353
<span class="head_info">
354-
<span id='cpu-temp'></span>
354+
<span id='cpu-total-power'><i class='fa fa-fw fa-plug'></i>_(Total)_ _(Power)_: N/A</span>
355355
</span>
356+
<?if (count($cpus)<2):?>
357+
<span class="head_info">
358+
<i class="fa fa-thermometer"></i> _(Temperature)_: <span id='cpu-temp0'>N/A</span>
359+
</span>
360+
<?endif;?>
356361
<span class="switch">
357362
_(Load)_:<span class="head_bar">
358363
<span class='cpu_ load'>0%</span>
@@ -398,22 +403,29 @@ switch ($themeHelper->getThemeName()) { // $themeHelper set in DefaultPageLayout
398403
</span>
399404
</td>
400405
</tr>
401-
406+
<tr>
402407
<?
403-
foreach ($cpus as $pair) {
404-
[$cpu1, $cpu2] = my_preg_split('/[,-]/',$pair);
405-
echo "<tr class='cpu_open'>";
406-
if ($is_intel_cpu && count($core_types) > 0)
407-
$core_type = "({$core_types[$cpu1]})";
408-
else
409-
$core_type = "";
410-
411-
if ($cpu2)
412-
echo "<td><span class='w26'>CPU $cpu1 $core_type - HT $cpu2 </span><span class='dashboard w36'><span class='cpu$cpu1 load resize'>0%</span><div class='usage-disk sys'><span id='cpu$cpu1'></span><span></span></div></span><span class='dashboard w36'><span class='cpu$cpu2 load resize'>0%</span><div class='usage-disk sys'><span id='cpu$cpu2'></span><span></span></div></span></td>";
413-
else
414-
echo "<td><span class='w26'>CPU $cpu1 $core_type</span><span class='w72'><span class='cpu$cpu1 load resize'>0%</span><div class='usage-disk sys'><span id='cpu$cpu1'></span><span></span></div></span></td>";
415-
echo "</tr>";
416-
}
408+
foreach ($cpus as $cpu_index=>$package) {
409+
if (count($cpus) > 1) {
410+
echo "<td><span class='cpu_open w72'><i class='fa fa-plug'></i> "._("Physical")." CPU $cpu_index "._("Power").": <span id='cpu-power$cpu_index'>N/A </span> ";
411+
if (count($cpus)>1) echo "<i class='fa fa-thermometer'></i> "._("Temperature").": <span id='cpu-temp$cpu_index'>N/A</span>";
412+
echo "</td></span></tr>";
413+
}
414+
foreach ($package as $pair) {
415+
[$cpu1, $cpu2] = my_preg_split('/[,-]/',$pair);
416+
echo "<tr class='cpu_open'>";
417+
if ($is_intel_cpu && count($core_types) > 0)
418+
$core_type = "({$core_types[$cpu1]})";
419+
else
420+
$core_type = "";
421+
422+
if ($cpu2)
423+
echo "<td><span class='w26'>CPU $cpu1 $core_type - HT $cpu2 </span><span class='dashboard w36'><span class='cpu$cpu1 load resize'>0%</span><div class='usage-disk sys'><span id='cpu$cpu1'></span><span></span></div></span><span class='dashboard w36'><span class='cpu$cpu2 load resize'>0%</span><div class='usage-disk sys'><span id='cpu$cpu2'></span><span></span></div></span></td>";
424+
else
425+
echo "<td><span class='w26'>CPU $cpu1 $core_type</span><span class='w72'><span class='cpu$cpu1 load resize'>0%</span><div class='usage-disk sys'><span id='cpu$cpu1'></span><span></span></div></span></td>";
426+
echo "</tr>";
427+
}
428+
}
417429
?>
418430
<tr id='cpu_chart'>
419431
<td>
@@ -1441,6 +1453,7 @@ var startup = true;
14411453
var stopgap = '<thead class="stopgap"><tr><td class="stopgap"></td></tr></thead>';
14421454
var recall = null;
14431455
var recover = null;
1456+
var tempunit="<?=_var($display,'unit','C');?>";
14441457

14451458
// Helper function to calculate millisPerPixel based on container width
14461459
function getMillisPerPixel(timeInSeconds, containerId) {
@@ -1695,6 +1708,39 @@ function addChartNet(rx, tx) {
16951708
txTimeSeries.append(now, Math.floor(tx / 1000));
16961709
}
16971710

1711+
function updateCPUPower() {
1712+
if (!cpupower) return;
1713+
1714+
// Update total power
1715+
const totalEl = document.getElementById('cpu-total-power');
1716+
const totalPower = cpupower.totalPower ?? 0;
1717+
if (totalEl) {
1718+
totalEl.innerHTML = `<i class="fa fa-fw fa-plug"></i> _(Total)_ _(Power)_: ${totalPower.toFixed(2)} W`;
1719+
}
1720+
1721+
// Update each core's span
1722+
const cpuspower = cpupower.power ?? [];
1723+
cpuspower.forEach((power, index) => {
1724+
const coreEl = document.getElementById(`cpu-power${index}`);
1725+
if (coreEl) {
1726+
coreEl.innerHTML = `${power.toFixed(2)} W`;
1727+
}
1728+
});
1729+
1730+
const cpustemps = cpupower.temp ?? [];
1731+
cpustemps.forEach((temp, index) => {
1732+
const coreTempEl = document.getElementById(`cpu-temp${index}`);
1733+
if (coreTempEl) {
1734+
tempdisplay = temp.toFixed(0);
1735+
if (tempunit === "F") {
1736+
tempdisplay = ((temp.toFixed(0))* 9 / 5) + 32;
1737+
}
1738+
coreTempEl.innerHTML = Math.round(tempdisplay)+`&#8201;&#176;`+tempunit;;
1739+
}
1740+
});
1741+
1742+
}
1743+
16981744
// Cache for last values to avoid unnecessary DOM updates
16991745
var lastCpuValues = {
17001746
load: -1,
@@ -2770,6 +2816,60 @@ $(function() {
27702816
setTimeout(function() {
27712817
// Charts initialized
27722818
},500);
2819+
2820+
2821+
2822+
// Start GraphQL CPU power subscription with retry logic
2823+
let cpuInitPWRAttempts = 0, cpuPWRRetryMs = 100;
2824+
function initPwrCpuSubscription() {
2825+
2826+
2827+
if (window.gql && window.apolloClient) {
2828+
// Define the subscription query when GraphQL is available
2829+
// corepower has the temps currently.
2830+
CPU_POWER_SUBSCRIPTION = window.gql(`
2831+
subscription SystemMetricsCpuTelemetry {
2832+
systemMetricsCpuTelemetry {
2833+
totalPower,
2834+
power,
2835+
temp,
2836+
}
2837+
}
2838+
`);
2839+
cpuPowerSubscription = window.apolloClient.subscribe({
2840+
query: CPU_POWER_SUBSCRIPTION
2841+
}).subscribe({
2842+
next: (result) => {
2843+
2844+
2845+
if (result.data?.systemMetricsCpuTelemetry){
2846+
cpupower = result.data.systemMetricsCpuTelemetry;
2847+
2848+
updateCPUPower();
2849+
}
2850+
},
2851+
error: (err) => {
2852+
console.error('CPU power subscription error:', err);
2853+
// Try to resubscribe with capped backoff
2854+
if (cpuPowerSubscription) { try { cpuPowerSubscription.unsubscribe(); } catch(e){} }
2855+
setTimeout(initPwrCpuSubscription, Math.min(cpuPWRRetryMs *= 2, 5000));
2856+
}
2857+
});
2858+
} else {
2859+
// Retry with capped backoff if GraphQL client not ready
2860+
cpuInitPWRAttempts++;
2861+
setTimeout(initPwrCpuSubscription, Math.min(cpuPWRRetryMs *= 2, 2000));
2862+
}
2863+
}
2864+
initPwrCpuSubscription();
2865+
// Cleanup GraphQL subscription on page unload
2866+
$(window).on('beforeunload', function() {
2867+
if (cpuPowerSubscription) {
2868+
cpuPowerSubscription.unsubscribe();
2869+
}
2870+
});
2871+
2872+
27732873

27742874
// Cleanup GraphQL subscription on page unload
27752875
$(window).on('beforeunload', function() {

emhttp/plugins/dynamix/include/Helpers.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,4 +854,21 @@ function display_deprecated_filesystem_warning($deprecated_disks, $type = 'array
854854

855855
return $html;
856856
}
857+
858+
function get_cpu_packages(string $separator = ','): array {
859+
$packages = [];
860+
foreach (glob("/sys/devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list") as $path) {
861+
$pkg_id = (int)file_get_contents(dirname($path) . "/physical_package_id");
862+
$siblings = str_replace(",", $separator, trim(file_get_contents($path)));
863+
if (!in_array($siblings, $packages[$pkg_id] ?? [])) {
864+
$packages[$pkg_id][] = $siblings;
865+
}
866+
}
867+
foreach ($packages as &$list) {
868+
$keys = array_map(fn($s) => (int)explode($separator, $s)[0], $list);
869+
array_multisort($keys, SORT_ASC, SORT_NUMERIC, $list);
870+
}
871+
unset($list);
872+
return $packages;
873+
}
857874
?>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
function get_cpu_packages(string $separator = ','): array {
3+
$packages = [];
4+
5+
foreach (glob("/sys/devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list") as $path) {
6+
$pkg_id = (int)file_get_contents(dirname($path) . "/physical_package_id");
7+
$siblings = str_replace(",", $separator, trim(file_get_contents($path)));
8+
9+
if (!in_array($siblings, $packages[$pkg_id] ?? [])) {
10+
$packages[$pkg_id][] = $siblings;
11+
}
12+
}
13+
14+
// Sort groups within each package by first CPU number
15+
foreach ($packages as &$list) {
16+
$keys = array_map(fn($s) => (int)explode($separator, $s)[0], $list);
17+
array_multisort($keys, SORT_ASC, SORT_NUMERIC, $list);
18+
}
19+
unset($list);
20+
21+
return $packages;
22+
}

0 commit comments

Comments
 (0)