No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Parley Hatch e084cd76ff Merge branch 'trace-and-thermals'
Broadens the trace from the CPU die to the whole board: every hwmon
temperature and fan, GPU columns, and disk throughput differenced from
/proc/diskstats. Adds run metadata, workload wrapping and an end-of-run
summary to the CLI around it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RBkv7V5GNmhMu8pv3JBT1D
2026-08-22 19:50:21 -06:00
src Trace the whole board, not just the die 2026-08-22 18:57:03 -06:00
.gitignore Initial commit: Pulse - A beautiful terminal system monitor 2025-12-09 09:46:14 -07:00
Cargo.lock Cut idle CPU from 6.0% to 1.3% of a core 2026-08-22 16:56:12 -06:00
Cargo.toml Cut idle CPU from 6.0% to 1.3% of a core 2026-08-22 16:56:12 -06:00
README.md Trace the whole board, not just the die 2026-08-22 18:57:03 -06:00

pulse

A real-time system monitoring dashboard for the terminal, and a trace recorder for the runs you want to keep.

Built for a Ryzen 9 9950X3D workstation running Omarchy, which is why it cares about per-CCD die temperatures, board sensors, and whether clocks held for the length of a burn-in.

The dashboard

pulse
key
q quit
t cycle theme
s cycle the process sort
r start / stop recording a trace
↑↓ move through the process table
K kill the selected process

The theme follows the Omarchy desktop palette and re-reads it when the desktop theme changes, until you cycle away with t.

Panels shrink and drop from the bottom of each column on a short terminal rather than drawing off the edge of the screen; the process table always survives.

Tracing

A trace is one tab-separated row per sample, flushed as it is written -- a run that ends in a hard lock still has every sample up to the moment it went down.

pulse -t burn.tsv                     # trace while you watch
pulse --headless -d 30m -t burn.tsv   # no TUI, stop after half an hour
pulse -- stress-ng --cpu 32           # trace exactly as long as the workload runs

Options:

flag
-t, --trace [FILE] start recording immediately; defaults to pulse-trace-<timestamp>.tsv
--headless record without drawing the TUI
-i, --interval DUR time between samples (default 1s)
-d, --duration DUR stop after this long; headless only
-n, --note TEXT free text recorded in the file's preamble
-f, --force overwrite an existing trace file
--summarize FILE report on a trace already on disk

Durations take a unit -- 500ms, 90s, 30m, 2h. A bare number is seconds.

What gets recorded

Roughly fifty columns, fixed at the moment recording starts and matched by name on every row, so a sensor that drops out mid-run leaves its own column blank instead of shifting every reading to its right onto the wrong header:

  • CPU: total and busiest-core percent, average and peak clock, 1/5/15 load
  • Memory: used, percent, swap
  • Network: rx and tx bytes per second
  • Disk: read, write, %util and queue depth per physical device, from /proc/diskstats -- partitions and device-mapper are skipped so traffic is not counted twice
  • GPU: utilisation, VRAM, temperature, fan and power, per device
  • Every plausible hwmon temperature: die and per-CCD, VRM, motherboard, both NVMe controllers, all four DIMMs, and fan RPM

The file opens with #-prefixed metadata -- pulse version, host, kernel, CPU and GPU, sample interval, the workload, and your --note. Readers skip those lines by default (pandas.read_csv(..., sep='\t', comment='#'), gnuplot, awk '/^#/ {next}').

The summary

Every run ends with the arithmetic nobody wants to do by hand on a two-thousand-row TSV:

pulse: 1980 samples over 33m 0s to burn.tsv
  cpu_pct       mean       99.8  peak      100.0  start→end      +0.0 (+0.0%)
  avg_mhz       mean     5142.0  peak     5163.0  start→end      -1.2 (-0.0%)
  Tctl          mean       78.2  peak       82.4  start→end      +0.1
  CPU_Opt_rpm   mean     1620.0  peak     1780.0  start→end     +42.0 (+2.7%)

start→end compares the mean of the first thirty samples against the last thirty -- half the run at each end if it is shorter than that -- so one scheduler hiccup in the final second does not read as thermal decay. No percentage is shown for temperatures: Celsius is an interval scale, and "3% hotter" is not a statement about anything.

An open-ended soak usually ends in Ctrl-C, which kills the process before it can report. pulse --summarize burn.tsv recomputes the same figures from the file, including one recorded months ago.

Building

cargo build --release
cp target/release/pulse ~/.cargo/bin/

NVIDIA GPU panels need NVML (the proprietary driver); without it the GPU panel says so and everything else works. Temperatures come from /sys/class/hwmon and need no privileges.