No description
  • C 99.1%
  • Makefile 0.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Emmett1 0b3de668a6 Add hogs, a TUI resource monitor
Lists running programs by CPU, memory, or disk I/O: program name on the
left, a proportional bar on the right. Everything comes from /proc, with
ncurses the only dependency.

- groups processes by program, so Firefox's content processes read as one
  firefox (x15) row rather than fifteen Isolated Web Co rows
- disk rates come from read_bytes/write_bytes, which skip the page cache;
  rows we cannot read show - rather than 0
- x signals the selected row, re-reading each PID first so a stale row
  cannot signal whatever inherited its PID; PID 1 is never signalled
- space freezes the display, and the cursor follows its program rather
  than a row number, so the sort order shifting does not move your aim

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZPgG8HFHXzdRmbc39knZF
2026-08-27 06:49:04 +08:00
.gitignore Add hogs, a TUI resource monitor 2026-08-27 06:49:04 +08:00
hogs.c Add hogs, a TUI resource monitor 2026-08-27 06:49:04 +08:00
Makefile Add hogs, a TUI resource monitor 2026-08-27 06:49:04 +08:00
README.md Add hogs, a TUI resource monitor 2026-08-27 06:49:04 +08:00

hogs

A small terminal monitor for what is using this machine: program name on the left, a proportional usage bar on the right.

 hogs      39 programs   8 cores   every 1.5s              sort:cpu  abs
 CPU  23.1%  ████████▏               MEM 4.5G/15G  ██████████
 PROGRAM                       CPU  USAGE (100% = one core)
 yes                         99.7%   ██████████████████████████████████████▊
 firefox (x15)               20.3%   ███████▋
 qemu-system-x86_64           3.9%   █▌
 claude (x2)                  3.3%   █▏

Sorting by disk instead (d) shows who is actually touching storage:

 PROGRAM                      DISK  DISK (read + write per second)
 dd                         1.2G/s   █████████████████████████████████████████
 journald                    412K/s   ▏
 postgres (x9)                  -

Build

make            # needs ncursesw
./hogs
make install    # optional, PREFIX=/usr/local

Keys

key what it does
q quit
c / m / d sort by CPU / by memory / by disk I/O
g group processes by program, or list them individually with PIDs
r bar scale: absolute (one core / all RAM) or relative to the busiest row
K show/hide kernel threads (shown in [brackets])
/ filter by name — Enter accepts, Esc clears
space freeze the display; sampling stops until you press it again
x, F9 signal the selected row — then t for SIGTERM, k for SIGKILL
+ / - slower / faster refresh
arrows, j/k, PgUp/PgDn, Home/End move the cursor; the list scrolls to follow

Notes

  • Everything comes from /proc; no privileges needed and no dependencies beyond ncurses.
  • CPU% is per core, so a program using two cores fully reads 200%. In absolute scaling the bar is full at 100% and marks the overflow with >.
  • Disk I/O is read_bytes + write_bytes from /proc/<pid>/io, which count bytes that actually reach storage rather than the page cache. That file is readable only for your own processes unless you are root, so other users' rows show -, meaning unknown rather than idle.
  • Disk rates have no natural full scale the way a core or total RAM does, so the bars are drawn against the recent peak, which decays between samples.
  • Freezing (space) leaves the numbers exactly as they were. The first sample after unfreezing averages CPU over the whole frozen span, so it can read low for one tick.
  • x signals the whole program when rows are grouped, so a row reading firefox (x15) sends the signal fifteen times; press g first to aim at a single PID. The prompt always names what it is about to signal.
  • The process list can be up to one refresh interval old, so before signalling a PID hogs re-reads it and checks it is still the same program. A row for a process that has since exited reports already gone rather than signalling whatever inherited its PID. PID 1 is never signalled.
  • The cursor follows the program it is on rather than a row number, so it stays put when the sort order shifts underneath it.
  • Memory is resident set size (RSS). Grouped rows add up the RSS of each process, which double counts memory that copies of a program share.
  • Names come from argv[0], falling back to the kernel's comm for kernel threads. That is why Firefox's content processes group under firefox rather than appearing as Isolated Web Co.