mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-09 23:15:38 -05:00
separate scripts
This commit is contained in:
@@ -10,6 +10,10 @@ import qs.Common
|
|||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
readonly property string shellDir: Qt.resolvedUrl(".").toString().replace(
|
||||||
|
"file://", "").replace("/Services/", "")
|
||||||
|
|
||||||
property int refCount: 0
|
property int refCount: 0
|
||||||
property int updateInterval: refCount > 0 ? 3000 : 30000
|
property int updateInterval: refCount > 0 ? 3000 : 30000
|
||||||
property int maxProcesses: 100
|
property int maxProcesses: 100
|
||||||
@@ -598,356 +602,9 @@ Singleton {
|
|||||||
onTriggered: root.updateAllStats()
|
onTriggered: root.updateAllStats()
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string staticDataScript: `exec 2>/dev/null
|
|
||||||
set -o pipefail
|
|
||||||
json_escape() { sed -e 's/\\\\/\\\\\\\\/g' -e 's/"/\\\\"/g' -e ':a;N;$!ba;s/\\n/\\\\n/g'; }
|
|
||||||
|
|
||||||
printf "{"
|
|
||||||
|
|
||||||
cpu_count=$(nproc)
|
|
||||||
cpu_model=$(grep -m1 'model name' /proc/cpuinfo | cut -d: -f2- | sed 's/^ *//' | json_escape || echo 'Unknown')
|
|
||||||
|
|
||||||
printf '"cpu":{"count":%d,"model":"%s"},' "$cpu_count" "$cpu_model"
|
|
||||||
|
|
||||||
dmip="/sys/class/dmi/id"
|
|
||||||
[ -d "$dmip" ] || dmip="/sys/devices/virtual/dmi/id"
|
|
||||||
mb_vendor=$([ -r "$dmip/board_vendor" ] && cat "$dmip/board_vendor" | json_escape || echo "Unknown")
|
|
||||||
mb_name=$([ -r "$dmip/board_name" ] && cat "$dmip/board_name" | json_escape || echo "")
|
|
||||||
bios_ver=$([ -r "$dmip/bios_version" ] && cat "$dmip/bios_version" | json_escape || echo "Unknown")
|
|
||||||
bios_date=$([ -r "$dmip/bios_date" ] && cat "$dmip/bios_date" | json_escape || echo "")
|
|
||||||
|
|
||||||
kern_ver=$(uname -r | json_escape)
|
|
||||||
distro=$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d= -f2- | tr -d '"' | json_escape || echo 'Unknown')
|
|
||||||
host_name=$(hostname | json_escape)
|
|
||||||
arch_name=$(uname -m)
|
|
||||||
|
|
||||||
printf '"system":{"kernel":"%s","distro":"%s","hostname":"%s","arch":"%s","motherboard":"%s %s","bios":"%s %s"},' \\
|
|
||||||
"$kern_ver" "$distro" "$host_name" "$arch_name" "$mb_vendor" "$mb_name" "$bios_ver" "$bios_date"
|
|
||||||
|
|
||||||
printf '"gpus":['
|
|
||||||
gfirst=1
|
|
||||||
tmp_gpu=$(mktemp)
|
|
||||||
|
|
||||||
# Map driver -> vendor, else infer from lspci line
|
|
||||||
infer_vendor() {
|
|
||||||
case "$1" in
|
|
||||||
nvidia|nouveau) echo NVIDIA ;;
|
|
||||||
amdgpu|radeon) echo AMD ;;
|
|
||||||
i915|xe) echo Intel ;;
|
|
||||||
*) case "$2" in
|
|
||||||
*NVIDIA*|*Nvidia*|*nvidia*) echo NVIDIA ;;
|
|
||||||
*AMD*|*ATI*|*amd*|*ati*) echo AMD ;;
|
|
||||||
*Intel*|*intel*) echo Intel ;;
|
|
||||||
*) echo Unknown ;;
|
|
||||||
esac ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# Priority for sorting (nvidia first, then dGPU AMD, then iGPU AMD/Intel)
|
|
||||||
prio_of() {
|
|
||||||
local drv="$1" bdf="$2"
|
|
||||||
case "$drv" in
|
|
||||||
nvidia) echo 3 ;;
|
|
||||||
amdgpu|radeon)
|
|
||||||
# crude: device number from BDF 0000:BB:DD.F -> DD
|
|
||||||
local dd="\${bdf##*:}"; dd="\${dd%%.*}"
|
|
||||||
[ "$dd" = "00" ] && echo 1 || echo 2
|
|
||||||
;;
|
|
||||||
i915|xe) echo 0 ;;
|
|
||||||
*) echo 0 ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# Enumerate all VGA/3D/2D/Display devices (domain-aware)
|
|
||||||
LC_ALL=C lspci -nnD 2>/dev/null | grep -iE ' VGA| 3D| 2D| Display' | while IFS= read -r line; do
|
|
||||||
bdf="\${line%% *}" # 0000:BB:DD.F
|
|
||||||
short_bdf="\${bdf#0000:}"
|
|
||||||
|
|
||||||
# kernel driver in use
|
|
||||||
drv=""; vendor="Unknown"
|
|
||||||
if [ -e "/sys/bus/pci/devices/\$bdf/driver" ]; then
|
|
||||||
drv="$(basename "$(readlink -f "/sys/bus/pci/devices/\$bdf/driver")")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
vendor="$(infer_vendor "\$drv" "\$line")"
|
|
||||||
|
|
||||||
# Just pass the raw line, we'll parse it in JavaScript
|
|
||||||
raw_line="$(printf '%s' "\$line" | json_escape)"
|
|
||||||
|
|
||||||
# priority for sorting
|
|
||||||
prio="$(prio_of "\$drv" "\$bdf")"
|
|
||||||
|
|
||||||
printf '%s|%s|%s|%s\\n' "\$prio" "\$drv" "\$vendor" "\$raw_line" >> "\$tmp_gpu"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Output JSON
|
|
||||||
if [ -s "\$tmp_gpu" ]; then
|
|
||||||
while IFS='|' read -r pr drv vendor raw_line; do
|
|
||||||
[ \$gfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"driver":"%s","vendor":"%s","rawLine":"%s"}' \\
|
|
||||||
"\$drv" "\$vendor" "\$raw_line"
|
|
||||||
gfirst=0
|
|
||||||
done < <(sort -t'|' -k1,1nr -k2,2 "\$tmp_gpu")
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f "\$tmp_gpu"
|
|
||||||
printf ']'
|
|
||||||
|
|
||||||
printf "}\\n"`
|
|
||||||
|
|
||||||
readonly property string dynamicDataScript: `
|
|
||||||
sort_key=\${1:-cpu}
|
|
||||||
max_procs=\${2:-20}
|
|
||||||
collect_gpu_temps=\${3:-0}
|
|
||||||
collect_nvidia_only=\${4:-0}
|
|
||||||
|
|
||||||
collect_non_nvidia=\${5:-1}
|
|
||||||
json_escape() { sed -e 's/\\\\/\\\\\\\\/g' -e 's/"/\\\\"/g' -e ':a;N;$!ba;s/\\n/\\\\n/g'; }
|
|
||||||
|
|
||||||
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 %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"
|
|
||||||
|
|
||||||
# Get pss per pid
|
|
||||||
get_pss_kb() {
|
|
||||||
# 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=0
|
|
||||||
for hwmon_dir in /sys/class/hwmon/hwmon*/; do
|
|
||||||
[ -d "$hwmon_dir" ] || continue
|
|
||||||
name_file="\${hwmon_dir}name"
|
|
||||||
[ -r "$name_file" ] || continue
|
|
||||||
|
|
||||||
# Check if this hwmon is for CPU temperature
|
|
||||||
if grep -qE 'coretemp|k10temp|k8temp|cpu_thermal|soc_thermal' "$name_file" 2>/dev/null; then
|
|
||||||
# Look for temperature files without using wildcards in quotes
|
|
||||||
for temp_file in "\${hwmon_dir}"temp*_input; do
|
|
||||||
if [ -r "$temp_file" ]; then
|
|
||||||
cpu_temp=$(awk '{printf "%.1f", $1/1000}' "$temp_file" 2>/dev/null || echo 0)
|
|
||||||
break 2 # Break both loops
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
printf '"cpu":{"count":%d,"model":"%s","frequency":%s,"temperature":%s,' \\
|
|
||||||
"$cpu_count" "$cpu_model" "$cpu_freq" "$cpu_temp"
|
|
||||||
|
|
||||||
printf '"total":'
|
|
||||||
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)
|
|
||||||
awk -v n="$cpu_cores" 'BEGIN{c=0}
|
|
||||||
/^cpu[0-9]+/ {
|
|
||||||
if(c>0) printf ",";
|
|
||||||
printf "[%d,%d,%d,%d,%d,%d,%d,%d]", $2,$3,$4,$5,$6,$7,$8,$9;
|
|
||||||
c++;
|
|
||||||
if(c==n) exit
|
|
||||||
}' /proc/stat
|
|
||||||
printf ']},'
|
|
||||||
|
|
||||||
printf '"network":['
|
|
||||||
tmp_net=$(mktemp)
|
|
||||||
grep -E '(wlan|eth|enp|wlp|ens|eno)' /proc/net/dev > "$tmp_net" || true
|
|
||||||
nfirst=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
iface=$(echo "$line" | awk '{print $1}' | sed 's/://')
|
|
||||||
rx_bytes=$(echo "$line" | awk '{print $2}')
|
|
||||||
tx_bytes=$(echo "$line" | awk '{print $10}')
|
|
||||||
[ $nfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"name":"%s","rx":%d,"tx":%d}' "$iface" "$rx_bytes" "$tx_bytes"
|
|
||||||
nfirst=0
|
|
||||||
done < "$tmp_net"
|
|
||||||
rm -f "$tmp_net"
|
|
||||||
printf '],'
|
|
||||||
|
|
||||||
printf '"disk":['
|
|
||||||
tmp_disk=$(mktemp)
|
|
||||||
grep -E ' (sd[a-z]+|nvme[0-9]+n[0-9]+|vd[a-z]+|dm-[0-9]+|mmcblk[0-9]+) ' /proc/diskstats > "$tmp_disk" || true
|
|
||||||
dfirst=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
name=$(echo "$line" | awk '{print $3}')
|
|
||||||
read_sectors=$(echo "$line" | awk '{print $6}')
|
|
||||||
write_sectors=$(echo "$line" | awk '{print $10}')
|
|
||||||
[ $dfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"name":"%s","read":%d,"write":%d}' "$name" "$read_sectors" "$write_sectors"
|
|
||||||
dfirst=0
|
|
||||||
done < "$tmp_disk"
|
|
||||||
rm -f "$tmp_disk"
|
|
||||||
printf '],'
|
|
||||||
|
|
||||||
printf '"processes":['
|
|
||||||
case "$sort_key" in
|
|
||||||
cpu) SORT_OPT="--sort=-pcpu" ;;
|
|
||||||
memory) SORT_OPT="--sort=-pmem" ;;
|
|
||||||
name) SORT_OPT="--sort=+comm" ;;
|
|
||||||
pid) SORT_OPT="--sort=+pid" ;;
|
|
||||||
*) SORT_OPT="--sort=-pcpu" ;;
|
|
||||||
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 pmem_rss rss_kib comm rest; do
|
|
||||||
[ -z "$pid" ] && continue
|
|
||||||
|
|
||||||
# Per-process CPU ticks (utime+stime)
|
|
||||||
pticks=$(awk '{print $14+$15}' "/proc/$pid/stat" 2>/dev/null || echo 0)
|
|
||||||
|
|
||||||
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_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"}')
|
|
||||||
|
|
||||||
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,"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"
|
|
||||||
printf '],'
|
|
||||||
|
|
||||||
load_avg=$(cut -d' ' -f1-3 /proc/loadavg)
|
|
||||||
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":{"loadavg":"%s","processes":%d,"threads":%d,"boottime":"%s"},' \\
|
|
||||||
"$load_avg" "$proc_count" "$thread_count" "$boot_time"
|
|
||||||
|
|
||||||
printf '"diskmounts":['
|
|
||||||
tmp_mounts=$(mktemp)
|
|
||||||
df -h --output=source,target,fstype,size,used,avail,pcent | tail -n +2 | grep -vE '^(tmpfs|devtmpfs)' | head -n 10 > "$tmp_mounts" || true
|
|
||||||
mfirst=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
device=$(echo "$line" | awk '{print $1}' | json_escape)
|
|
||||||
mount=$(echo "$line" | awk '{print $2}' | json_escape)
|
|
||||||
fstype=$(echo "$line" | awk '{print $3}')
|
|
||||||
size=$(echo "$line" | awk '{print $4}')
|
|
||||||
used=$(echo "$line" | awk '{print $5}')
|
|
||||||
avail=$(echo "$line" | awk '{print $6}')
|
|
||||||
percent=$(echo "$line" | awk '{print $7}')
|
|
||||||
[ $mfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"device":"%s","mount":"%s","fstype":"%s","size":"%s","used":"%s","avail":"%s","percent":"%s"}' \\
|
|
||||||
"$device" "$mount" "$fstype" "$size" "$used" "$avail" "$percent"
|
|
||||||
mfirst=0
|
|
||||||
done < "$tmp_mounts"
|
|
||||||
rm -f "$tmp_mounts"
|
|
||||||
printf ']',
|
|
||||||
|
|
||||||
printf '"gputemps":['
|
|
||||||
if [ "$collect_gpu_temps" = "1" ]; then
|
|
||||||
gfirst=1
|
|
||||||
tmp_gpu=$(mktemp)
|
|
||||||
|
|
||||||
# Gather GPU temperatures only
|
|
||||||
for card in /sys/class/drm/card*; do
|
|
||||||
[ -e "$card/device/driver" ] || continue
|
|
||||||
|
|
||||||
drv=$(basename "$(readlink -f "$card/device/driver")")
|
|
||||||
drv=\${drv##*/}
|
|
||||||
|
|
||||||
# Temperature (only scan hwmon for non-NVIDIA GPUs)
|
|
||||||
hw=""; temp="0"
|
|
||||||
if [ "$collect_non_nvidia" = "1" ]; then
|
|
||||||
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
|
|
||||||
fi
|
|
||||||
|
|
||||||
# NVIDIA temperature fallback
|
|
||||||
if [ "$drv" = "nvidia" ] && [ "$temp" = "0" ] && [ "$collect_nvidia_only" = "1" ] && 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
|
|
||||||
|
|
||||||
[ "$temp" != "0" ] && {
|
|
||||||
[ $gfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"driver":"%s","hwmon":"%s","temperature":%s}' "$drv" "\${hw:-unknown}" "\${temp:-0}"
|
|
||||||
gfirst=0
|
|
||||||
}
|
|
||||||
done
|
|
||||||
|
|
||||||
# Fallback if no DRM cards found but nvidia-smi is available
|
|
||||||
if [ $gfirst -eq 1 ] && [ \"$collect_nvidia_only\" = \"1\" ]; then
|
|
||||||
if command -v nvidia-smi >/dev/null 2>&1; then
|
|
||||||
temp=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null | head -1)
|
|
||||||
[ -n "$temp" ] && {
|
|
||||||
printf '{"driver":"nvidia","hwmon":"nvidia","temperature":%s}' "$temp"
|
|
||||||
gfirst=0
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f "$tmp_gpu"
|
|
||||||
fi
|
|
||||||
printf ']'
|
|
||||||
|
|
||||||
printf "}\\n"`
|
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: staticDataProcess
|
id: staticDataProcess
|
||||||
command: ["bash", "-c", "bash -s <<'QS_EOF'\n"
|
command: [root.shellDir + "/sysmon_static.sh"]
|
||||||
+ root.staticDataScript + "\nQS_EOF\n"]
|
|
||||||
running: false
|
running: false
|
||||||
onExited: exitCode => {
|
onExited: exitCode => {
|
||||||
if (exitCode !== 0) {
|
if (exitCode !== 0) {
|
||||||
@@ -979,8 +636,7 @@ readonly property string staticDataScript: `exec 2>/dev/null
|
|||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: dynamicStatsProcess
|
id: dynamicStatsProcess
|
||||||
command: ["bash", "-c", "bash -s \"$1\" \"$2\" \"$3\" \"$4\" \"$5\" <<'QS_EOF'\n"
|
command: [root.shellDir + "/sysmon_dynamic.sh", root.sortBy, String(root.maxProcesses), root.hasGpuTempWidgets() ? "1" : "0", root.hasNvidiaGpuTempWidgets() ? "1" : "0", root.hasNonNvidiaGpuTempWidgets() ? "1" : "0"]
|
||||||
+ root.dynamicDataScript + "\nQS_EOF\n", "-", root.sortBy, String(root.maxProcesses), root.hasGpuTempWidgets() ? "1" : "0", root.hasNvidiaGpuTempWidgets() ? "1" : "0", root.hasNonNvidiaGpuTempWidgets() ? "1" : "0"]
|
|
||||||
running: false
|
running: false
|
||||||
onExited: exitCode => {
|
onExited: exitCode => {
|
||||||
if (exitCode !== 0) {
|
if (exitCode !== 0) {
|
||||||
|
|||||||
254
sysmon_dynamic.sh
Executable file
254
sysmon_dynamic.sh
Executable file
@@ -0,0 +1,254 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Outputs dynamic system stats as JSON.
|
||||||
|
# Args:
|
||||||
|
# $1 sort_key (cpu|memory|name|pid)
|
||||||
|
# $2 max_procs
|
||||||
|
# $3 collect_gpu_temps (0/1)
|
||||||
|
# $4 collect_nvidia_only (0/1)
|
||||||
|
# $5 collect_non_nvidia (0/1)
|
||||||
|
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
sort_key=${1:-cpu}
|
||||||
|
max_procs=${2:-20}
|
||||||
|
collect_gpu_temps=${3:-0}
|
||||||
|
collect_nvidia_only=${4:-0}
|
||||||
|
collect_non_nvidia=${5:-1}
|
||||||
|
|
||||||
|
json_escape() { sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e ':a;N;$!ba;s/\n/\\n/g'; }
|
||||||
|
|
||||||
|
printf "{"
|
||||||
|
|
||||||
|
# ---- Memory block (exact fields/keys) ----
|
||||||
|
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 %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"
|
||||||
|
|
||||||
|
# ---- Helper: PSS in KiB ----
|
||||||
|
get_pss_kb() {
|
||||||
|
local pid="$1" k v rest total=0 f
|
||||||
|
f="/proc/$pid/smaps_rollup"
|
||||||
|
if [ -r "$f" ]; then
|
||||||
|
while read -r k v rest; 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
|
||||||
|
while read -r k v rest; do
|
||||||
|
if [ "$k" = "Pss:" ]; then
|
||||||
|
: "${v:=0}"
|
||||||
|
total=$(( total + v ))
|
||||||
|
fi
|
||||||
|
done < "$f"
|
||||||
|
printf '%s\n' "$total"; return
|
||||||
|
fi
|
||||||
|
printf '0\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- CPU (meta + temp) ----
|
||||||
|
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=0
|
||||||
|
for hwmon_dir in /sys/class/hwmon/hwmon*/; do
|
||||||
|
[ -d "$hwmon_dir" ] || continue
|
||||||
|
name_file="${hwmon_dir}name"
|
||||||
|
[ -r "$name_file" ] || continue
|
||||||
|
if grep -qE 'coretemp|k10temp|k8temp|cpu_thermal|soc_thermal' "$name_file" 2>/dev/null; then
|
||||||
|
for temp_file in "${hwmon_dir}"temp*_input; do
|
||||||
|
[ -r "$temp_file" ] || continue
|
||||||
|
cpu_temp=$(awk '{printf "%.1f", $1/1000}' "$temp_file" 2>/dev/null || echo 0)
|
||||||
|
break 2
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
printf '"cpu":{"count":%d,"model":"%s","frequency":%s,"temperature":%s,' \
|
||||||
|
"$cpu_count" "$cpu_model" "$cpu_freq" "$cpu_temp"
|
||||||
|
|
||||||
|
# cpu.total (first line of /proc/stat, fields 2..)
|
||||||
|
printf '"total":'
|
||||||
|
awk 'NR==1 {
|
||||||
|
printf "[";
|
||||||
|
for(i=2; i<=NF; i++) { if(i>2) printf ","; printf "%d", $i; }
|
||||||
|
printf "]";
|
||||||
|
exit
|
||||||
|
}' /proc/stat
|
||||||
|
|
||||||
|
# cpu.cores (each cpuN line, 8 columns)
|
||||||
|
printf ',"cores":['
|
||||||
|
cpu_cores=$(nproc)
|
||||||
|
awk -v n="$cpu_cores" 'BEGIN{c=0}
|
||||||
|
/^cpu[0-9]+/ {
|
||||||
|
if(c>0) printf ",";
|
||||||
|
printf "[%d,%d,%d,%d,%d,%d,%d,%d]", $2,$3,$4,$5,$6,$7,$8,$9;
|
||||||
|
c++;
|
||||||
|
if(c==n) exit
|
||||||
|
}' /proc/stat
|
||||||
|
printf ']},'
|
||||||
|
|
||||||
|
# ---- Network (rx/tx bytes per iface) ----
|
||||||
|
printf '"network":['
|
||||||
|
tmp_net=$(mktemp)
|
||||||
|
grep -E '(wlan|eth|enp|wlp|ens|eno)' /proc/net/dev > "$tmp_net" || true
|
||||||
|
nfirst=1
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[ -z "$line" ] && continue
|
||||||
|
iface=$(echo "$line" | awk '{print $1}' | sed 's/://')
|
||||||
|
rx_bytes=$(echo "$line" | awk '{print $2}')
|
||||||
|
tx_bytes=$(echo "$line" | awk '{print $10}')
|
||||||
|
[ $nfirst -eq 1 ] || printf ","
|
||||||
|
printf '{"name":"%s","rx":%d,"tx":%d}' "$iface" "$rx_bytes" "$tx_bytes"
|
||||||
|
nfirst=0
|
||||||
|
done < "$tmp_net"
|
||||||
|
rm -f "$tmp_net"
|
||||||
|
printf '],'
|
||||||
|
|
||||||
|
# ---- Disk (/proc/diskstats sectors; read/write) ----
|
||||||
|
printf '"disk":['
|
||||||
|
tmp_disk=$(mktemp)
|
||||||
|
grep -E ' (sd[a-z]+|nvme[0-9]+n[0-9]+|vd[a-z]+|dm-[0-9]+|mmcblk[0-9]+) ' /proc/diskstats > "$tmp_disk" || true
|
||||||
|
dfirst=1
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[ -z "$line" ] && continue
|
||||||
|
name=$(echo "$line" | awk '{print $3}')
|
||||||
|
read_sectors=$(echo "$line" | awk '{print $6}')
|
||||||
|
write_sectors=$(echo "$line" | awk '{print $10}')
|
||||||
|
[ $dfirst -eq 1 ] || printf ","
|
||||||
|
printf '{"name":"%s","read":%d,"write":%d}' "$name" "$read_sectors" "$write_sectors"
|
||||||
|
dfirst=0
|
||||||
|
done < "$tmp_disk"
|
||||||
|
rm -f "$tmp_disk"
|
||||||
|
printf '],'
|
||||||
|
|
||||||
|
# ---- Processes (shape & fields match your QML) ----
|
||||||
|
case "$sort_key" in
|
||||||
|
cpu) SORT_OPT="--sort=-pcpu" ;;
|
||||||
|
memory) SORT_OPT="--sort=-pmem" ;;
|
||||||
|
name) SORT_OPT="--sort=+comm" ;;
|
||||||
|
pid) SORT_OPT="--sort=+pid" ;;
|
||||||
|
*) SORT_OPT="--sort=-pcpu" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
printf '"processes":['
|
||||||
|
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 line; do
|
||||||
|
[ -z "$line" ] && continue
|
||||||
|
# split the first 6 columns, rest is full command tail
|
||||||
|
pid=$( awk '{print $1}' <<<"$line")
|
||||||
|
ppid=$( awk '{print $2}' <<<"$line")
|
||||||
|
cpu=$( awk '{print $3}' <<<"$line")
|
||||||
|
pmem=$( awk '{print $4}' <<<"$line")
|
||||||
|
rss_kib=$(awk '{print $5}' <<<"$line")
|
||||||
|
comm=$( awk '{print $6}' <<<"$line")
|
||||||
|
rest=$( printf '%s\n' "$line" | cut -d' ' -f7- )
|
||||||
|
|
||||||
|
# CPU ticks (utime+stime)
|
||||||
|
pticks=$(awk '{print $14+$15}' "/proc/$pid/stat" 2>/dev/null || echo 0)
|
||||||
|
|
||||||
|
# PSS in KiB and % of MemTotal
|
||||||
|
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_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"}')
|
||||||
|
|
||||||
|
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,"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"
|
||||||
|
printf '],'
|
||||||
|
|
||||||
|
# ---- System (dynamic bits) ----
|
||||||
|
load_avg=$(cut -d' ' -f1-3 /proc/loadavg)
|
||||||
|
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":{"loadavg":"%s","processes":%d,"threads":%d,"boottime":"%s"},' \
|
||||||
|
"$load_avg" "$proc_count" "$thread_count" "$boot_time"
|
||||||
|
|
||||||
|
# ---- Mounts (same df -h shape/strings) ----
|
||||||
|
printf '"diskmounts":['
|
||||||
|
tmp_mounts=$(mktemp)
|
||||||
|
df -h --output=source,target,fstype,size,used,avail,pcent | tail -n +2 | grep -vE '^(tmpfs|devtmpfs)' > "$tmp_mounts" || true
|
||||||
|
mfirst=1
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[ -z "$line" ] && continue
|
||||||
|
device=$(echo "$line" | awk '{print $1}' | json_escape)
|
||||||
|
mount=$( echo "$line" | awk '{print $2}' | json_escape)
|
||||||
|
fstype=$(echo "$line" | awk '{print $3}')
|
||||||
|
size=$( echo "$line" | awk '{print $4}')
|
||||||
|
used=$( echo "$line" | awk '{print $5}')
|
||||||
|
avail=$( echo "$line" | awk '{print $6}')
|
||||||
|
percent=$(echo "$line" | awk '{print $7}')
|
||||||
|
[ $mfirst -eq 1 ] || printf ","
|
||||||
|
printf '{"device":"%s","mount":"%s","fstype":"%s","size":"%s","used":"%s","avail":"%s","percent":"%s"}' \
|
||||||
|
"$device" "$mount" "$fstype" "$size" "$used" "$avail" "$percent"
|
||||||
|
mfirst=0
|
||||||
|
done < "$tmp_mounts"
|
||||||
|
rm -f "$tmp_mounts"
|
||||||
|
printf '],'
|
||||||
|
|
||||||
|
# ---- GPU temps (optional) ----
|
||||||
|
printf '"gputemps":['
|
||||||
|
if [ "$collect_gpu_temps" = "1" ]; then
|
||||||
|
gfirst=1
|
||||||
|
for card in /sys/class/drm/card*; do
|
||||||
|
[ -e "$card/device/driver" ] || continue
|
||||||
|
drv=$(basename "$(readlink -f "$card/device/driver")"); drv=${drv##*/}
|
||||||
|
hw=""; temp="0"
|
||||||
|
|
||||||
|
if [ "$collect_non_nvidia" = "1" ]; then
|
||||||
|
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
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$drv" = "nvidia" ] && [ "$temp" = "0" ] && [ "$collect_nvidia_only" = "1" ] && 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
|
||||||
|
|
||||||
|
if [ "$temp" != "0" ]; then
|
||||||
|
[ $gfirst -eq 1 ] || printf ","
|
||||||
|
printf '{"driver":"%s","hwmon":"%s","temperature":%s}' "$drv" "${hw:-unknown}" "${temp:-0}"
|
||||||
|
gfirst=0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Fallback: nvidia-smi only
|
||||||
|
if [ ${gfirst:-1} -eq 1 ] && [ "$collect_nvidia_only" = "1" ] && command -v nvidia-smi >/dev/null 2>&1; then
|
||||||
|
temp=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null | head -1)
|
||||||
|
[ -n "$temp" ] && printf '{"driver":"nvidia","hwmon":"nvidia","temperature":%s}' "$temp"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
printf ']'
|
||||||
|
|
||||||
|
printf "}\n"
|
||||||
81
sysmon_static.sh
Executable file
81
sysmon_static.sh
Executable file
@@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Outputs static system info + detected GPUs as JSON (no temps)
|
||||||
|
|
||||||
|
set -o pipefail
|
||||||
|
exec 2>/dev/null
|
||||||
|
|
||||||
|
json_escape() { sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e ':a;N;$!ba;s/\n/\\n/g'; }
|
||||||
|
|
||||||
|
printf "{"
|
||||||
|
|
||||||
|
cpu_count=$(nproc)
|
||||||
|
cpu_model=$(grep -m1 'model name' /proc/cpuinfo | cut -d: -f2- | sed 's/^ *//' | json_escape || echo 'Unknown')
|
||||||
|
printf '"cpu":{"count":%d,"model":"%s"},' "$cpu_count" "$cpu_model"
|
||||||
|
|
||||||
|
dmip="/sys/class/dmi/id"
|
||||||
|
[ -d "$dmip" ] || dmip="/sys/devices/virtual/dmi/id"
|
||||||
|
mb_vendor=$([ -r "$dmip/board_vendor" ] && cat "$dmip/board_vendor" | json_escape || echo "Unknown")
|
||||||
|
mb_name=$([ -r "$dmip/board_name" ] && cat "$dmip/board_name" | json_escape || echo "")
|
||||||
|
bios_ver=$([ -r "$dmip/bios_version" ] && cat "$dmip/bios_version" | json_escape || echo "Unknown")
|
||||||
|
bios_date=$([ -r "$dmip/bios_date" ] && cat "$dmip/bios_date" | json_escape || echo "")
|
||||||
|
|
||||||
|
kern_ver=$(uname -r | json_escape)
|
||||||
|
distro=$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d= -f2- | tr -d '"' | json_escape || echo 'Unknown')
|
||||||
|
host_name=$(hostname | json_escape)
|
||||||
|
arch_name=$(uname -m)
|
||||||
|
|
||||||
|
printf '"system":{"kernel":"%s","distro":"%s","hostname":"%s","arch":"%s","motherboard":"%s %s","bios":"%s %s"},' \
|
||||||
|
"$kern_ver" "$distro" "$host_name" "$arch_name" "$mb_vendor" "$mb_name" "$bios_ver" "$bios_date"
|
||||||
|
|
||||||
|
printf '"gpus":['
|
||||||
|
gfirst=1
|
||||||
|
tmp_gpu=$(mktemp)
|
||||||
|
|
||||||
|
infer_vendor() {
|
||||||
|
case "$1" in
|
||||||
|
nvidia|nouveau) echo NVIDIA ;;
|
||||||
|
amdgpu|radeon) echo AMD ;;
|
||||||
|
i915|xe) echo Intel ;;
|
||||||
|
*) case "$2" in
|
||||||
|
*NVIDIA*|*Nvidia*|*nvidia*) echo NVIDIA ;;
|
||||||
|
*AMD*|*ATI*|*amd*|*ati*) echo AMD ;;
|
||||||
|
*Intel*|*intel*) echo Intel ;;
|
||||||
|
*) echo Unknown ;;
|
||||||
|
esac ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
prio_of() {
|
||||||
|
local drv="$1" bdf="$2"
|
||||||
|
case "$drv" in
|
||||||
|
nvidia) echo 3 ;;
|
||||||
|
amdgpu|radeon)
|
||||||
|
local dd="${bdf##*:}"; dd="${dd%%.*}"
|
||||||
|
[ "$dd" = "00" ] && echo 1 || echo 2
|
||||||
|
;;
|
||||||
|
i915|xe) echo 0 ;;
|
||||||
|
*) echo 0 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
LC_ALL=C lspci -nnD 2>/dev/null | grep -iE ' VGA| 3D| 2D| Display' | while IFS= read -r line; do
|
||||||
|
bdf="${line%% *}"
|
||||||
|
drv=""
|
||||||
|
[ -e "/sys/bus/pci/devices/$bdf/driver" ] && drv="$(basename "$(readlink -f "/sys/bus/pci/devices/$bdf/driver")")"
|
||||||
|
vendor="$(infer_vendor "$drv" "$line")"
|
||||||
|
raw_line="$(printf '%s' "$line" | json_escape)"
|
||||||
|
prio="$(prio_of "$drv" "$bdf")"
|
||||||
|
printf '%s|%s|%s|%s\n' "$prio" "$drv" "$vendor" "$raw_line" >> "$tmp_gpu"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -s "$tmp_gpu" ]; then
|
||||||
|
while IFS='|' read -r pr drv vendor raw_line; do
|
||||||
|
[ $gfirst -eq 1 ] || printf ","
|
||||||
|
printf '{"driver":"%s","vendor":"%s","rawLine":"%s"}' "$drv" "$vendor" "$raw_line"
|
||||||
|
gfirst=0
|
||||||
|
done < <(sort -t'|' -k1,1nr -k2,2 "$tmp_gpu")
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$tmp_gpu"
|
||||||
|
printf ']'
|
||||||
|
printf "}\n"
|
||||||
Reference in New Issue
Block a user