1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00

fix process monitor CPU calculations

This commit is contained in:
bbedward
2025-08-02 14:55:33 -04:00
parent 21c40b58bc
commit 2cf7497324
2 changed files with 63 additions and 71 deletions

View File

@@ -29,13 +29,9 @@ Column {
spacing: Theme.spacingM
Component.onCompleted: {
SysMonitorService.addRef();
SysMonitorService.addRef();
// Trigger immediate updates for both services
SysMonitorService.updateAllStats();
}
Component.onDestruction: {
SysMonitorService.removeRef();
SysMonitorService.removeRef();
}
Rectangle {
@@ -107,7 +103,7 @@ Column {
spacing: 6
Repeater {
model: SysMonitorService.perCoreCpuUsage.length
model: SysMonitorService.perCoreCpuUsage
Row {
width: parent.width
@@ -130,11 +126,11 @@ Column {
anchors.verticalCenter: parent.verticalCenter
Rectangle {
width: parent.width * Math.min(1, SysMonitorService.perCoreCpuUsage[index] / 100)
width: parent.width * Math.min(1, modelData / 100)
height: parent.height
radius: parent.radius
color: {
const usage = SysMonitorService.perCoreCpuUsage[index];
const usage = modelData;
if (usage > 80)
return Theme.error;
@@ -156,7 +152,7 @@ Column {
}
StyledText {
text: SysMonitorService.perCoreCpuUsage[index] ? SysMonitorService.perCoreCpuUsage[index].toFixed(0) + "%" : "0%"
text: modelData ? modelData.toFixed(0) + "%" : "0%"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText

View File

@@ -1,6 +1,5 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
@@ -8,18 +7,15 @@ import qs.Services
Singleton {
id: root
property int refCount: 0
property int updateInterval: refCount > 0 ? 2000 : 30000
property int maxProcesses: 100
property bool isUpdating: false
// Process data
property var processes: []
property string sortBy: "cpu"
property bool sortDescending: true
// System stats
property real cpuUsage: 0
property real totalCpuUsage: 0
property int cpuCores: 1
@@ -29,7 +25,9 @@ Singleton {
property real cpuTemperature: 0
property var perCoreCpuUsage: []
// Memory stats
property var lastCpuStats: null
property var lastPerCoreStats: null
property real memoryUsage: 0
property real totalMemoryMB: 0
property real usedMemoryMB: 0
@@ -40,18 +38,15 @@ Singleton {
property int totalSwapKB: 0
property int usedSwapKB: 0
// Network stats
property real networkRxRate: 0
property real networkTxRate: 0
property var lastNetworkStats: null
// Disk stats
property real diskReadRate: 0
property real diskWriteRate: 0
property var lastDiskStats: null
property var diskMounts: []
// History
property int historySize: 60
property var cpuHistory: []
property var memoryHistory: []
@@ -64,7 +59,6 @@ Singleton {
"write": []
})
// System info
property string kernelVersion: ""
property string distribution: ""
property string hostname: ""
@@ -82,7 +76,7 @@ Singleton {
updateAllStats();
}
}
function removeRef() {
refCount = Math.max(0, refCount - 1);
}
@@ -100,7 +94,7 @@ Singleton {
sortProcessesInPlace();
}
}
function toggleSortOrder() {
sortDescending = !sortDescending;
sortProcessesInPlace();
@@ -151,13 +145,32 @@ Singleton {
Quickshell.execDetached("kill", [pid.toString()]);
}
}
function addToHistory(array, value) {
array.push(value);
if (array.length > historySize)
array.shift();
}
function calculateCpuUsage(currentStats, lastStats) {
if (!lastStats || !currentStats || currentStats.length < 4) {
return 0;
}
const currentTotal = currentStats.reduce((sum, val) => sum + val, 0);
const lastTotal = lastStats.reduce((sum, val) => sum + val, 0);
const totalDiff = currentTotal - lastTotal;
if (totalDiff <= 0) return 0;
const currentIdle = currentStats[3];
const lastIdle = lastStats[3];
const idleDiff = currentIdle - lastIdle;
const usedDiff = totalDiff - idleDiff;
return Math.max(0, Math.min(100, (usedDiff / totalDiff) * 100));
}
function parseUnifiedStats(text) {
function num(x) {
return (typeof x === "number" && !isNaN(x)) ? x : 0;
@@ -172,25 +185,23 @@ Singleton {
return;
}
// Memory
if (data.memory) {
const m = data.memory;
totalMemoryKB = num(m.total);
const free = num(m.free);
const buf = num(m.buffers);
const cached = num(m.cached);
const shared = num(m.shared);
usedMemoryKB = totalMemoryKB - free - buf - cached;
totalSwapKB = num(m.swaptotal);
usedSwapKB = num(m.swaptotal) - num(m.swapfree);
totalMemoryMB = totalMemoryKB / 1024;
usedMemoryMB = usedMemoryKB / 1024;
freeMemoryMB = (totalMemoryKB - usedMemoryKB) / 1024;
availableMemoryMB= (free + buf + cached) / 1024;
availableMemoryMB= num(m.available) ? num(m.available) / 1024 : (free + buf + cached) / 1024;
memoryUsage = totalMemoryKB > 0 ? (usedMemoryKB / totalMemoryKB) * 100 : 0;
}
// CPU
if (data.cpu) {
cpuCores = data.cpu.count || 1;
cpuCount = data.cpu.count || 1;
@@ -199,42 +210,36 @@ Singleton {
cpuTemperature = data.cpu.temperature || 0;
if (data.cpu.total && data.cpu.total.length >= 8) {
const user = data.cpu.total[0];
const nice = data.cpu.total[1];
const system = data.cpu.total[2];
const idle = data.cpu.total[3];
const iowait = data.cpu.total[4];
const irq = data.cpu.total[5];
const softirq = data.cpu.total[6];
const total = user + nice + system + idle + iowait + irq + softirq;
const used = total - idle - iowait;
const usage = total > 0 ? (used / total) * 100 : 0;
const currentStats = data.cpu.total;
const usage = calculateCpuUsage(currentStats, lastCpuStats);
cpuUsage = usage;
totalCpuUsage = usage;
lastCpuStats = [...currentStats];
}
if (data.cpu.cores) {
const coreUsages = [];
for (const coreStats of data.cpu.cores) {
if (coreStats && coreStats.length >= 8) {
const user = coreStats[0];
const nice = coreStats[1];
const system = coreStats[2];
const idle = coreStats[3];
const iowait = coreStats[4];
const irq = coreStats[5];
const softirq = coreStats[6];
const total = user + nice + system + idle + iowait + irq + softirq;
const used = total - idle - iowait;
const usage = total > 0 ? (used / total) * 100 : 0;
for (let i = 0; i < data.cpu.cores.length; i++) {
const currentCoreStats = data.cpu.cores[i];
if (currentCoreStats && currentCoreStats.length >= 8) {
let lastCoreStats = null;
if (lastPerCoreStats && lastPerCoreStats[i]) {
lastCoreStats = lastPerCoreStats[i];
}
const usage = calculateCpuUsage(currentCoreStats, lastCoreStats);
coreUsages.push(usage);
}
}
perCoreCpuUsage = coreUsages;
if (JSON.stringify(perCoreCpuUsage) !== JSON.stringify(coreUsages)) {
perCoreCpuUsage = coreUsages;
}
lastPerCoreStats = data.cpu.cores.map(core => [...core]);
}
}
// Network
if (data.network) {
let totalRx = 0;
let totalTx = 0;
@@ -254,7 +259,6 @@ Singleton {
lastNetworkStats = { "rx": totalRx, "tx": totalTx };
}
// Disk
if (data.disk) {
let totalRead = 0;
let totalWrite = 0;
@@ -274,7 +278,6 @@ Singleton {
lastDiskStats = { "read": totalRead, "write": totalWrite };
}
// Processes
if (data.processes) {
const newProcesses = [];
for (const proc of data.processes) {
@@ -293,7 +296,6 @@ Singleton {
sortProcessesInPlace();
}
// System info
if (data.system) {
kernelVersion = data.system.kernel || "";
distribution = data.system.distro || "";
@@ -311,14 +313,12 @@ Singleton {
diskMounts = data.diskmounts;
}
// Update history
addToHistory(cpuHistory, cpuUsage);
addToHistory(memoryHistory, memoryUsage);
isUpdating = false;
}
// Utility functions
function getProcessIcon(command) {
const cmd = command.toLowerCase();
if (cmd.includes("firefox") || cmd.includes("chrome") || cmd.includes("browser"))
@@ -335,11 +335,11 @@ Singleton {
return "settings";
return "memory";
}
function formatCpuUsage(cpu) {
return (cpu || 0).toFixed(1) + "%";
}
function formatMemoryUsage(memoryKB) {
const mem = memoryKB || 0;
if (mem < 1024)
@@ -349,7 +349,7 @@ Singleton {
else
return (mem / (1024 * 1024)).toFixed(1) + " GB";
}
function formatSystemMemory(memoryKB) {
const mem = memoryKB || 0;
if (mem < 1024 * 1024)
@@ -375,7 +375,6 @@ Singleton {
} else {
console.log("SysMonitorService: System active, resuming monitoring")
if (root.refCount > 0) {
// Trigger immediate update when coming back from idle
root.updateAllStats()
}
}
@@ -384,6 +383,7 @@ Singleton {
readonly property string scriptBody: `set -Eeuo pipefail
trap 'echo "ERR at line $LINENO: $BASH_COMMAND (exit $?)" >&2' ERR
sort_key=\${1:-cpu}
max_procs=\${2:-20}
@@ -393,15 +393,16 @@ printf "{"
mem_line="$(awk '/^MemTotal:/{t=$2}
/^MemFree:/{f=$2}
/^MemAvailable:/{a=$2}
/^Buffers:/{b=$2}
/^Cached:/{c=$2}
/^Shmem:/{s=$2}
/^SwapTotal:/{st=$2}
/^SwapFree:/{sf=$2}
END{printf "%d %d %d %d %d %d",t,f,b,c,st,sf}' /proc/meminfo)"
read -r MT MF BU CA ST SF <<< "$mem_line"
printf '"memory":{"total":%d,"free":%d,"buffers":%d,"cached":%d,"swaptotal":%d,"swapfree":%d},' \\
"$MT" "$MF" "$BU" "$CA" "$ST" "$SF"
END{printf "%d %d %d %d %d %d %d %d",t,f,a,b,c,s,st,sf}' /proc/meminfo)"
read -r MT MF MA BU CA SH ST SF <<< "$mem_line"
printf '"memory":{"total":%d,"free":%d,"available":%d,"buffers":%d,"cached":%d,"shared":%d,"swaptotal":%d,"swapfree":%d},' \\
"$MT" "$MF" "$MA" "$BU" "$CA" "$SH" "$ST" "$SF"
cpu_count=$(nproc)
cpu_model=$(grep -m1 'model name' /proc/cpuinfo | cut -d: -f2- | sed 's/^ *//' | json_escape || echo 'Unknown')
@@ -457,7 +458,7 @@ while IFS= read -r line; do
dfirst=0
done < "$tmp_disk"
rm -f "$tmp_disk"
printf ']',
printf '],'
printf '"processes":['
case "$sort_key" in
@@ -470,7 +471,6 @@ esac
tmp_ps=$(mktemp)
ps -eo pid,ppid,pcpu,pmem,rss,comm,cmd --no-headers $SORT_OPT | head -n "$max_procs" > "$tmp_ps" || true
pfirst=1
while IFS=' ' read -r pid ppid cpu memp memk comm rest; do
[ -z "$pid" ] && continue
@@ -481,7 +481,7 @@ while IFS=' ' read -r pid ppid cpu memp memk comm rest; do
pfirst=0
done < "$tmp_ps"
rm -f "$tmp_ps"
printf ']',
printf '],'
dmip="/sys/class/dmi/id"
[ -d "$dmip" ] || dmip="/sys/devices/virtual/dmi/id"
@@ -539,26 +539,22 @@ printf "}\\n"`
isUpdating = false;
}
}
stdout: StdioCollector {
onStreamFinished: {
if (text.trim()) {
const fullText = text.trim();
const lastBraceIndex = fullText.lastIndexOf('}');
if (lastBraceIndex === -1) {
console.error("SysMonitorService: No JSON object found in output.", fullText);
isUpdating = false;
return;
}
const jsonText = fullText.substring(0, lastBraceIndex + 1);
try {
const data = JSON.parse(jsonText);
parseUnifiedStats(jsonText);
} catch (e) {
console.error("BROKEN JSON:", e, "Cleaned Text:", jsonText);
isUpdating = false;
return;
}