System Monitor: add history sparklines and a top-process list - #25
Open
havokentity wants to merge 2 commits into
Open
System Monitor: add history sparklines and a top-process list#25havokentity wants to merge 2 commits into
havokentity wants to merge 2 commits into
Conversation
The panel could say the CPU was at 40% but not whether that was a spike settling or a climb, and never said which process was responsible — the two questions anyone actually opens a system monitor to answer. Each of the CPU, memory and network cards now carries a sparkline of the last minute, and a card at the foot lists the five busiest processes ranked by CPU or by memory. The history is a fixed-capacity ring rather than an array that grows. This tool is a login item that stays up for months, and it has already shipped one bug of exactly the long-uptime shape — the kernel's integer_t CPU tick counters read back negative past 2^31 and made the load report zero — so the storage is allocated once at sixty samples, the write cursor is taken modulo the capacity every append, and the fill level saturates. Nothing added here counts upwards without a bound, including the process-refresh cadence, which is a countdown that resets rather than a tick total. The series-to-points mapping is a pure nonisolated function separate from the Shape, because its failure mode is invisible rather than loud: an idle machine reports the same figure for a minute straight, and normalising against that zero range puts a NaN in the Path, which CoreGraphics answers by silently dropping the whole shape. So a flat series falls back to a line down the middle, out-of-domain values are clamped, and a stray non-finite sample is neutralised before it can poison the series minimum and maximum for every other point. CPU and memory are plotted against a fixed 0...1 axis so an idle machine looks idle instead of having its 2% jitter redrawn as a mountain range; the two network traces share one axis derived from their combined peak, since scaled independently the upstream line would draw just as tall as a downstream forty times its size. The process list shells out to ps, which is far too expensive to do on the one-second poll and would reshuffle faster than anyone can read. Rather than add a second timer it divides the existing one, running every fifth poll, and the subprocess and its exit wait happen in a detached task so the main actor never blocks. A run that fails leaves the previous list on screen rather than blanking it, and rows are padded to a fixed five so the card cannot resize the panel underneath the user. Making room for all of this meant the panel grew, so its height is now derived from the same constants the popover lays its content out with instead of being a separate literal, and the settings sheet is capped against it. That cap fixes a latent 4pt overhang: the sheet was a hard-coded 338 against a 370pt panel, and PreferencesOverlay adds 18pt of padding per side. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The top-process list rides on the metric poll at a fifth of its rate, but it rode on it unconditionally: `start` is called at launch and `stop` only at termination, so the five-second `ps -A` ran whether or not anything was displaying the result. This tool ships as a login item, which means the common case is a machine where the panel is opened rarely or never — and there the cost was 17,280 subprocess spawns a day, around a tenth of a second of mostly system time apiece enumerating every process on the box, to compute a snapshot nobody could see. On battery that is timer-driven wakeups and roughly a percent of a core burned forever for nothing. Gate the listing on whether the list is on screen. The panel's own onDidShow/onDidClose hooks drive the flag rather than togglePopover, so a dismissal by outside click, by a display-parameter change or by a Space switch stops the sampling exactly as a deliberate close does. A show primes the list immediately and zeroes the countdown, so opening the panel does not sit in front of an empty or stale list while a leftover count drains; a closed panel parks the countdown at zero for the same reason. The metrics themselves are Mach counters costing next to nothing, so they keep polling every second and the tray strip is unaffected. The sampler is injectable so the cadence can be proved without launching a subprocess, and the tests assert call counts on the real poll path: zero listings across a closed panel's polls, one on show, one per divider while open, none again after close. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Wave 2 Phase A.
Implementation: System Monitor: add history sparklines and a top-process list
Review fixes: System Monitor: stop running ps while the panel is closed
Built by an isolated agent, then adversarially reviewed by an independent agent that checked the branch out and ran
swift build+ the full suite itself. Every review finding was fixed, with a regression test added for each high and medium.🤖 Generated with Claude Code