mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-09 15:05:39 -05:00
feat: add temperature widgets, separate ram/cpu widgets, update
calculations - make CPU calculations per-process mirror gnome (of all CPUs)
This commit is contained in:
@@ -8,21 +8,23 @@ import qs.Services
|
||||
Singleton {
|
||||
id: root
|
||||
property int refCount: 0
|
||||
property int updateInterval: refCount > 0 ? 2000 : 30000
|
||||
property int updateInterval: refCount > 0 ? 3000 : 30000
|
||||
property int maxProcesses: 100
|
||||
property bool isUpdating: false
|
||||
|
||||
property var processes: []
|
||||
property string sortBy: "cpu"
|
||||
property bool sortDescending: true
|
||||
|
||||
property var lastProcTicks: ({})
|
||||
property real lastTotalJiffies: -1
|
||||
|
||||
property real cpuUsage: 0
|
||||
property real totalCpuUsage: 0
|
||||
property int cpuCores: 1
|
||||
property int cpuCount: 1
|
||||
property string cpuModel: ""
|
||||
property real cpuFrequency: 0
|
||||
property real cpuTemperature: 0
|
||||
property real cpuTemperature: -1
|
||||
property var perCoreCpuUsage: []
|
||||
|
||||
property var lastCpuStats: null
|
||||
@@ -69,6 +71,7 @@ Singleton {
|
||||
property string bootTime: ""
|
||||
property string motherboard: ""
|
||||
property string biosVersion: ""
|
||||
property var availableGpus: []
|
||||
|
||||
function addRef() {
|
||||
refCount++;
|
||||
@@ -277,19 +280,43 @@ Singleton {
|
||||
}
|
||||
lastDiskStats = { "read": totalRead, "write": totalWrite };
|
||||
}
|
||||
|
||||
|
||||
let totalDiff = 0;
|
||||
if (data.cpu && data.cpu.total && data.cpu.total.length >= 4) {
|
||||
const currentTotal = data.cpu.total.reduce((s,v)=>s+v, 0);
|
||||
if (lastTotalJiffies > 0)
|
||||
totalDiff = currentTotal - lastTotalJiffies;
|
||||
lastTotalJiffies = currentTotal;
|
||||
}
|
||||
|
||||
if (data.processes) {
|
||||
const newProcesses = [];
|
||||
for (const proc of data.processes) {
|
||||
const pid = proc.pid;
|
||||
const pticks = Number(proc.pticks) || 0;
|
||||
const prev = lastProcTicks[pid] ?? null;
|
||||
let cpuShare = 0;
|
||||
|
||||
if (prev !== null && totalDiff > 0) {
|
||||
// Per share all CPUs (matches gnome system monitor)
|
||||
cpuShare = 100 * Math.max(0, pticks - prev) / totalDiff;
|
||||
|
||||
// per-share per-core
|
||||
//cpuShare = 100 * cpuCores * Math.max(0, pticks - prev) / totalDiff;
|
||||
}
|
||||
|
||||
lastProcTicks[pid] = pticks; // update cache
|
||||
|
||||
newProcesses.push({
|
||||
"pid": proc.pid,
|
||||
"pid": pid,
|
||||
"ppid": proc.ppid,
|
||||
"cpu": proc.cpu,
|
||||
"cpu": cpuShare,
|
||||
"memoryPercent": proc.pssPercent ?? proc.memoryPercent,
|
||||
"memoryKB": proc.pssKB ?? proc.memoryKB,
|
||||
"command": proc.command,
|
||||
"fullCommand": proc.fullCommand,
|
||||
"displayName": proc.command.length > 15 ? proc.command.substring(0, 15) + "..." : proc.command
|
||||
"displayName": (proc.command && proc.command.length > 15)
|
||||
? proc.command.substring(0, 15) + "..." : proc.command
|
||||
});
|
||||
}
|
||||
processes = newProcesses;
|
||||
@@ -313,6 +340,10 @@ Singleton {
|
||||
diskMounts = data.diskmounts;
|
||||
}
|
||||
|
||||
if (data.gpus) {
|
||||
availableGpus = data.gpus;
|
||||
}
|
||||
|
||||
addToHistory(cpuHistory, cpuUsage);
|
||||
addToHistory(memoryHistory, memoryUsage);
|
||||
|
||||
@@ -358,32 +389,16 @@ Singleton {
|
||||
return (mem / (1024 * 1024)).toFixed(1) + " GB";
|
||||
}
|
||||
|
||||
function getCpuTempCentigrade() {
|
||||
cpuTempProcess.running = true;
|
||||
}
|
||||
|
||||
|
||||
Timer {
|
||||
id: updateTimer
|
||||
interval: root.updateInterval
|
||||
running: root.refCount > 0 && !IdleService.isIdle
|
||||
running: root.refCount > 0
|
||||
repeat: true
|
||||
triggeredOnStart: true
|
||||
onTriggered: root.updateAllStats()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: IdleService
|
||||
function onIdleChanged(idle) {
|
||||
if (idle) {
|
||||
console.log("SysMonitorService: System idle, pausing monitoring")
|
||||
} else {
|
||||
console.log("SysMonitorService: System active, resuming monitoring")
|
||||
if (root.refCount > 0) {
|
||||
root.updateAllStats()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly property string scriptBody: `set -Eeuo pipefail
|
||||
trap 'echo "ERR at line $LINENO: $BASH_COMMAND (exit $?)" >&2' ERR
|
||||
@@ -410,28 +425,53 @@ printf '"memory":{"total":%d,"free":%d,"available":%d,"buffers":%d,"cached":%d,"
|
||||
|
||||
# Get pss per pid
|
||||
get_pss_kb() {
|
||||
local pid="$1"
|
||||
if [ -r "/proc/$pid/smaps_rollup" ]; then
|
||||
awk '/^Pss:/{print $2; exit}' "/proc/$pid/smaps_rollup"
|
||||
elif [ -r "/proc/$pid/smaps" ]; then
|
||||
awk '/^Pss:/{t+=$2} END{print t+0}' "/proc/$pid/smaps"
|
||||
else
|
||||
echo 0
|
||||
# Read PSS with zero external processes.
|
||||
# 1) Prefer smaps_rollup (fast, single file)
|
||||
# 2) Fallback to summing PSS in smaps
|
||||
# Return 0 if unavailable.
|
||||
local pid="$1" f total v k _
|
||||
f="/proc/$pid/smaps_rollup"
|
||||
if [ -r "$f" ]; then
|
||||
# smaps_rollup has one Pss: line — read it directly
|
||||
while read -r k v _; do
|
||||
if [ "$k" = "Pss:" ]; then
|
||||
printf '%s\n' "\${v:-0}"
|
||||
return
|
||||
fi
|
||||
done < "$f"
|
||||
printf '0\n'
|
||||
return
|
||||
fi
|
||||
f="/proc/$pid/smaps"
|
||||
if [ -r "$f" ]; then
|
||||
total=0
|
||||
while read -r k v _; do
|
||||
[ "$k" = "Pss:" ] && total=$(( total + (v:-0) ))
|
||||
done < "$f"
|
||||
printf '%s\n' "$total"
|
||||
return
|
||||
fi
|
||||
printf '0\n'
|
||||
}
|
||||
|
||||
cpu_count=$(nproc)
|
||||
cpu_model=$(grep -m1 'model name' /proc/cpuinfo | cut -d: -f2- | sed 's/^ *//' | json_escape || echo 'Unknown')
|
||||
cpu_freq=$(awk -F: '/cpu MHz/{gsub(/ /,"",$2);print $2;exit}' /proc/cpuinfo || echo 0)
|
||||
cpu_temp=$(if [ -r /sys/class/thermal/thermal_zone0/temp ]; then
|
||||
awk '{printf "%.1f",$1/1000}' /sys/class/thermal/thermal_zone0/temp 2>/dev/null || echo 0
|
||||
else echo 0; fi)
|
||||
cpu_temp=$(grep -l 'coretemp\\|k10temp\\|k8temp\\|cpu_thermal\\|soc_thermal' /sys/class/hwmon/hwmon*/name 2>/dev/null | sed 's/name$/temp1_input/' | xargs cat 2>/dev/null | awk '{print $1/1000}' | head -1 || echo 0)
|
||||
|
||||
printf '"cpu":{"count":%d,"model":"%s","frequency":%s,"temperature":%s,' \\
|
||||
"$cpu_count" "$cpu_model" "$cpu_freq" "$cpu_temp"
|
||||
|
||||
printf '"total":'
|
||||
awk 'NR==1 {printf "[%d,%d,%d,%d,%d,%d,%d,%d]", $2,$3,$4,$5,$6,$7,$8,$9; exit}' /proc/stat
|
||||
awk 'NR==1 {
|
||||
printf "[";
|
||||
for(i=2; i<=NF; i++) {
|
||||
if(i>2) printf ",";
|
||||
printf "%d", $i;
|
||||
}
|
||||
printf "]";
|
||||
exit
|
||||
}' /proc/stat
|
||||
|
||||
printf ',"cores":['
|
||||
cpu_cores=$(nproc)
|
||||
@@ -492,23 +532,19 @@ pfirst=1
|
||||
while IFS=' ' read -r pid ppid cpu pmem_rss rss_kib comm rest; do
|
||||
[ -z "$pid" ] && continue
|
||||
|
||||
# Optionally skip kernel threads / empty RSS lines (uncomment to filter)
|
||||
# [ "$rss_kib" -eq 0 ] && continue
|
||||
# Per-process CPU ticks (utime+stime)
|
||||
pticks=$(awk '{print $14+$15}' "/proc/$pid/stat" 2>/dev/null || echo 0)
|
||||
|
||||
pss_kib=$(get_pss_kb "$pid" 2>/dev/null || true)
|
||||
# Force numeric default if empty or non-numeric
|
||||
if [ "\${rss_kib:-0}" -eq 0 ]; then pss_kib=0; else pss_kib=$(get_pss_kb "$pid"); fi
|
||||
case "$pss_kib" in (''|*[!0-9]*) pss_kib=0 ;; esac
|
||||
|
||||
# PSS-based percent (locale-safe)
|
||||
pss_pct=$(LC_ALL=C awk -v p="$pss_kib" -v t="$MT" 'BEGIN{if(t>0) printf "%.2f", (100*p)/t; else printf "0.00"}')
|
||||
|
||||
# Build full command; escape both fields
|
||||
cmd=$(printf "%s %s" "$comm" "\${rest:-}" | json_escape)
|
||||
comm_esc=$(printf "%s" "$comm" | json_escape)
|
||||
|
||||
[ "$pfirst" -eq 1 ] || printf ","
|
||||
printf '{"pid":%s,"ppid":%s,"cpu":%s,"memoryPercent":%s,"memoryKB":%s,"pssKB":%s,"pssPercent":%s,"command":"%s","fullCommand":"%s"}' \
|
||||
"$pid" "$ppid" "$cpu" "$pss_pct" "$rss_kib" "$pss_kib" "$pss_pct" "$comm_esc" "$cmd"
|
||||
[ $pfirst -eq 1 ] || printf ","
|
||||
printf '{"pid":%s,"ppid":%s,"cpu":%s,"pticks":%s,"memoryPercent":%s,"memoryKB":%s,"pssKB":%s,"pssPercent":%s,"command":"%s","fullCommand":"%s"}' \
|
||||
"$pid" "$ppid" "$cpu" "$pticks" "$pss_pct" "$rss_kib" "$pss_kib" "$pss_pct" "$comm_esc" "$cmd"
|
||||
pfirst=0
|
||||
done < "$tmp_ps"
|
||||
rm -f "$tmp_ps"
|
||||
@@ -526,8 +562,8 @@ distro=$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d= -f2- | tr -d '"'
|
||||
host_name=$(hostname | json_escape)
|
||||
arch_name=$(uname -m)
|
||||
load_avg=$(cut -d' ' -f1-3 /proc/loadavg)
|
||||
proc_count=$(( $(ps aux | wc -l) - 1 ))
|
||||
thread_count=$(ps -eL | wc -l)
|
||||
proc_count=$(ls -Ud /proc/[0-9]* 2>/dev/null | wc -l)
|
||||
thread_count=$(ls -Ud /proc/[0-9]*/task/[0-9]* 2>/dev/null | wc -l)
|
||||
boot_time=$(who -b 2>/dev/null | awk '{print $3, $4}' | json_escape || echo 'Unknown')
|
||||
|
||||
printf '"system":{"kernel":"%s","distro":"%s","hostname":"%s","arch":"%s","loadavg":"%s","processes":%d,"threads":%d,"boottime":"%s","motherboard":"%s %s","bios":"%s %s"},' \\
|
||||
@@ -552,6 +588,78 @@ while IFS= read -r line; do
|
||||
mfirst=0
|
||||
done < "$tmp_mounts"
|
||||
rm -f "$tmp_mounts"
|
||||
printf ']',
|
||||
|
||||
printf '"gpus":['
|
||||
gfirst=1
|
||||
tmp_gpu=$(mktemp)
|
||||
|
||||
# Gather cards via DRM (much cheaper than lspci each tick)
|
||||
for card in /sys/class/drm/card*; do
|
||||
[ -e "$card/device/driver" ] || continue
|
||||
|
||||
drv=$(basename "$(readlink -f "$card/device/driver")") # e.g. nvidia, amdgpu, i915
|
||||
drv=\${drv##*/}
|
||||
|
||||
# Determine PCI secondary bus to help identify integrated vs discrete
|
||||
pci_path=$(readlink -f "$card/device") # .../0000:01:00.0
|
||||
func=\${pci_path##*/} # 0000:01:00.0
|
||||
sec=\${func#*:}; sec=\${sec%%:*} # "01" from 0000:01:00.0
|
||||
|
||||
# Priority: higher = more likely dedicated
|
||||
prio=0
|
||||
case "$drv" in
|
||||
nvidia) prio=3 ;; # dGPU
|
||||
amdgpu|radeon)
|
||||
if [ "$sec" = "00" ]; then prio=1; else prio=2; fi # APU often on bus 00
|
||||
;;
|
||||
i915) prio=0 ;; # iGPU
|
||||
*) prio=0 ;;
|
||||
esac
|
||||
|
||||
# Temperature via per-device hwmon if available
|
||||
hw=""; temp="0"
|
||||
for h in "$card/device"/hwmon/hwmon*; do
|
||||
[ -e "$h/temp1_input" ] || continue
|
||||
hw=$(basename "$h")
|
||||
temp=$(awk '{printf "%.1f",$1/1000}' "$h/temp1_input" 2>/dev/null || echo "0")
|
||||
break
|
||||
done
|
||||
|
||||
# NVIDIA fallback: use nvidia-smi (first GPU) if temp still 0
|
||||
if [ "$drv" = "nvidia" ] && command -v nvidia-smi >/dev/null 2>&1; then
|
||||
t=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null | head -1)
|
||||
[ -n "$t" ] && { temp="$t"; hw="\${hw:-nvidia}"; }
|
||||
fi
|
||||
|
||||
printf '%s|%s|%s|%s\n' "$prio" "$drv" "\${hw:-unknown}" "\${temp:-0}" >> "$tmp_gpu"
|
||||
done
|
||||
|
||||
# Fallback if no DRM cards found (keep drivers but still sort)
|
||||
if [ ! -s "$tmp_gpu" ]; then
|
||||
for drv in nvidia amdgpu radeon i915; do
|
||||
command -v "$drv" >/dev/null 2>&1 || true
|
||||
prio=0; [ "$drv" = "nvidia" ] && prio=3
|
||||
[ "$drv" = "amdgpu" ] && prio=2
|
||||
[ "$drv" = "radeon" ] && prio=2
|
||||
[ "$drv" = "i915" ] && prio=0
|
||||
temp="0"; hw="$drv"
|
||||
if [ "$drv" = "nvidia" ] && command -v nvidia-smi >/dev/null 2>&1; then
|
||||
t=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null | head -1)
|
||||
[ -n "$t" ] && temp="$t"
|
||||
fi
|
||||
printf '%s|%s|%s|%s\n' "$prio" "$drv" "$hw" "$temp" >> "$tmp_gpu"
|
||||
done
|
||||
fi
|
||||
|
||||
# Sort by priority (desc), then driver name for stability, and emit SAME JSON shape
|
||||
while IFS='|' read -r pr drv hw temp; do
|
||||
[ $gfirst -eq 1 ] || printf ","
|
||||
printf '{"driver":"%s","hwmon":"%s","temperature":%s}' "$drv" "$hw" "$temp"
|
||||
gfirst=0
|
||||
done < <(sort -t'|' -k1,1nr -k2,2 "$tmp_gpu")
|
||||
|
||||
rm -f "$tmp_gpu"
|
||||
printf ']'
|
||||
|
||||
printf "}\\n"`
|
||||
@@ -559,9 +667,9 @@ printf "}\\n"`
|
||||
Process {
|
||||
id: unifiedStatsProcess
|
||||
command: [
|
||||
"bash", "-c",
|
||||
"bash -s \"$1\" \"$2\" <<'QS_EOF'\\n" + root.scriptBody + "\\nQS_EOF\\n",
|
||||
"qsmon", root.sortBy, root.maxProcesses
|
||||
"bash", "-c",
|
||||
"bash -s \"$1\" \"$2\" <<'QS_EOF'\n" + root.scriptBody + "\nQS_EOF\n",
|
||||
root.sortBy, String(root.maxProcesses)
|
||||
]
|
||||
running: false
|
||||
onExited: (exitCode) => {
|
||||
@@ -594,17 +702,5 @@ printf "}\\n"`
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: cpuTempProcess
|
||||
command: ["bash", "-c", "grep -l 'coretemp\\|k10temp\\|k8temp\\|cpu_thermal\\|soc_thermal' /sys/class/hwmon/hwmon*/name | sed 's/name$/temp1_input/' | xargs cat | awk '{print $1/1000}'"]
|
||||
running: false
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const temp = parseFloat(text.trim());
|
||||
if (!isNaN(temp)) {
|
||||
cpuTemperature = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user