# Performance panel design A performance panel that drops from the island's status pill: CPU, RAM, temperatures, GPU, disks and network, ported from the four conky widgets that show them today (`system`, `gpu`, `disks`, `network` in conky-theme-udt). An icon in the status pill opens it and turns yellow or red when something needs attention, including the public IP drifting from the address the user's VPN depends on. This is sub-project 4 of the roadmap in `2026-10-07-island-core-design.md`. Once the panel is verified, the four conky widgets are removed: two dashboards drawing the same numbers would drift apart. ## Scope In v1: - A 3-column card grid: CPU (per-core bars, RAM, temperatures), GPU, network (rate graph, LAN and public IP, pin button), disks. - A status-pill icon tinted by the worst severity of temperatures, RAM, disks and the public IP check. - A pinned public IP, set from the panel, and a red warning on mismatch. - Removal of the four conky widgets and their samplers. Not in v1: a drawer page (sub-project 6 reuses `Perf.qml`); history beyond the network graph; process lists; GPU utilisation (the xe driver exposes none, see below); auto-discovered mounts; a keybind. ## Where it lives desktop/island/perf/ Perf.js pure parsing and maths, node-tested test_perf.js node test for Perf.js Perf.qml singleton: FileViews, Processes, Timers; exposes state PerfPanel.qml the card grid desktop/island/StatusPill.qml + the performance icon desktop/island/Island.qml + panel "perf" desktop/Prefs.qml + pinnedIp ## Data sources All of these are what conky reads today; nothing new is measured. | Figure | Source | When | | --- | --- | --- | | CPU load, aggregate | `/proc/stat` deltas | always, 2s | | CPU load, per core | `/proc/stat` `cpuN` lines | panel open, 2s | | RAM | `/proc/meminfo`, `MemTotal - MemAvailable` | always, 2s | | temperatures | hwmon `temp*_input` | always, 2s | | GPU fan | hwmon `xe` `fan1_input` | panel open, 2s | | VRAM used | `/proc/[0-9]*/fdinfo/*`, `drm-resident-vram0` summed per `drm-client-id` for `drm-driver: xe` | panel open, 2s | | disks | `timeout 5 /usr/bin/df -P -B1 ` | always, 60s | | network rate | `/sys/class/net/br0/statistics/{rx,tx}_bytes` | panel open, 1s | | LAN address | `ip -4 addr show br0`, memoized on first success | panel open | | public IP | `curl -fsS --max-time 10 https://ipinfo.io/ip` | 30 min, and on panel open if stale | Reads of `/proc` and `/sys` are `FileView`s reloaded by a `Timer`, no subprocess. `df`, the fdinfo scan, `ip` and `curl` are `Process` calls; each `Process` reused for a sequence sets `running = false` before each start. `Perf.detailed` is true while the panel is open and gates the rows marked "panel open", the way `Virsh.sampling` gates the VM stats. The always rows exist so the icon can warn while the panel is closed. ### Sensors hwmon chips are found by their `name` file once at start, because `hwmonN` numbering changes across boots. The table is conky's: | Chip | File | Label | Warn | Crit | | --- | --- | --- | --- | --- | | `k10temp` | `temp1_input` | CPU | 75 | 90 | | `k10temp` | `temp3_input` | CCD1 | 75 | 90 | | `nvme` | `temp1_input` | NVME | 60 | 70 | | `gigabyte_wmi` | `temp2_input` | BOARD | 60 | 70 | | `gigabyte_wmi` | `temp3_input` | BOARD | 60 | 70 | | `xe` | `temp2_input` | GPU | 75 | 85 | | `xe` | `temp3_input` | VRAM | 80 | 90 | The GPU has no utilisation figure: xe exposes no `gpu_busy_percent` and `intel_gpu_top` refuses the device. The integrated AMD GPU is not shown. ### Host constants Kept in `Perf.qml`, each marked `ponytail:` with its ceiling, as conky had them: the mount list (`/`, `/home`, `/data`, `/mnt/nfs/Library`, `/mnt/nfs/shared`, one NFS mount per server), the interface `br0` (a bridge, so VM-to-host traffic shows in the graph), and 12 GiB of VRAM (xe puts no capacity in sysfs). Mount icons are conky's, re-checked in Inconsolata Nerd Font: Slackware for `/`, house for `/home`, hard disk for `/data`, network share for NFS, where the label is the server address read from the mount's device field, so no address is committed. ## Public IP The fetch writes conky's cache format to `~/.cache/udt/pubip.txt` (`ip ` and `fetched ` lines, atomic), so the existing file is reused. A response that is not an IPv4 address is discarded and the cache left alone. A value older than 4 hours is shown as a dash. A pin button beside the address stores the current address as `perf.pinnedIp` in `desktop.json` through `Prefs`, which gains a `pinnedIp` property and `setPinnedIp()`, written only on change like `setControls()`. The address lives in the user's state file, never in the repo. Pressing the pin again with the same address does nothing; a different address replaces it. The check: | State | Result | | --- | --- | | no pin | ok | | fresh fetch equals pin | ok | | fresh fetch differs from pin | crit | | fetch failed, or value stale | ok; the last value while under 4 hours old, a dash after | A failed fetch is never a mismatch: a dropped connection must not raise the alarm. ## The icon `utilities-system-monitor` through `Quickshell.iconPath`, placed before the controls icon in the status pill. A dot on its top-right corner shows the worst severity; `IconImage` cannot be recoloured without an effect layer, and a dot reads as well: | Input | Warn | Crit | | --- | --- | --- | | each temperature | its warn | its crit | | RAM | 85% | 95% | | each disk | 90% | 95% | | public IP | | mismatch with the pin | No dot when ok, a `Theme.yellow` dot on warn, a `Theme.red` dot on crit. Not the accent, which udt can snap onto a state colour. CPU load is left out: spikes are normal and would flicker the dot, and sustained load shows up as heat. Left-click toggles the panel. No right-click until a drawer page exists. The status pill expands for `perf` as it does for `sound` and `controls`. ## The panel A grid of three columns, the same palette and type as the other island panels: - **CPU**, spanning two rows: aggregate load as the headline, the CPU model, one bar per core, RAM used and total with a bar, then the temperature rows for CPU, CCD1, NVME and both BOARD sensors. - **GPU**: package temperature as the headline, VRAM used and total with a bar, VRAM temperature, fan rpm. - **Network**: download and upload as two lines over a 60-point history, current rates, LAN address, public IP with its pin button. The public IP is red on mismatch. - **Disks**, spanning two columns: one row per mount with icon, label, percentage and bar. Colours follow conky's bands so the numbers read as before: load, per-core bars, RAM and disk bars at 25 and 75; temperatures at each sensor's own warn and crit. Escape closes the panel, as for the other panels. ## Errors - A missing chip, file or interface shows a dash and counts as ok for the icon. - `df` under `timeout 5`: a hung NFS server keeps the last value, or a dash before there is one. The island never blocks. - VRAM counts only processes readable by the user, so a system service's GPU use is missing. Noted as a ceiling, as in conky. - The network history is cleared when the panel closes; it is not sampled while closed. ## Conky removal In conky-theme-udt, after the panel is verified on screen beside the conky widgets, in that repo's own commits: - Delete `widgets/system.lua`, `gpu.lua`, `disks.lua`, `network.lua` and their entries in the `dashboard.lua` layout. - Drop `disks-sample.sh` and `pubip-sample.sh` from `conky.text` and delete them; the island owns the public IP fetch, and two fetchers would double the outside traffic. - Remove readers in `lib/data.lua` used only by those widgets, each checked against its remaining callers. - Leave the other widgets where they are. Rearranging the freed space is the user's call, on screen. ## Testing - `node desktop/island/perf/test_perf.js`: `/proc/stat` aggregate and per-core deltas, meminfo, `df -P -B1` parsing, the fdinfo sum with duplicate client ids, the network rate across a counter reset, severity across every input, the IP check (no pin, match, mismatch, failed, stale), and the cache file format both ways. - A smoke run of `qs -p desktop` reading the log, after the user restarts the desktop component, since the new directory needs a reindex. - On screen, by the user: the panel beside the conky widgets before they are removed, the icon colours, the pin button. ## AGENTS.md Add any gotcha found while building. The island's README gains the panel and the icon thresholds.