A Linux utility to graph resource usage of a process and its subprocesses over time. It uses procfs to record memory, CPU, I/O, thread, and file descriptor metrics for a process tree, outputting timestamped snapshots in JSON Lines format. Recordings can be visualized as terminal line charts or summary tables.
- Linux kernel >= 3.5 (uses
/proc/[pid]/task/[tid]/childrenfor subprocess discovery) - Go 1.26+
go install github.com/supakeen/pgr/cmd/pgr@latest
Or build from source:
git clone https://github.com/supakeen/pgr.git
cd pgr
go build ./cmd/pgr
Record resource usage of a process and all its descendants:
pgr record --pid <PID>
Options:
| Flag | Short | Default | Description |
|---|---|---|---|
--pid |
-p |
Root process ID to monitor (required) | |
--interval |
-i |
1s |
Sampling interval (Go duration) |
--output |
-o |
stdout | Output file path |
--long-names |
-l |
false |
Use full command name from /proc/[pid]/cmdline instead of the kernel 15-char comm name |
Examples:
# Record PID 1234 every second to stdout
pgr record -p 1234
# Record every 500ms to a file
pgr record -p 1234 -i 500ms -o recording.jsonl
# Record with full command names
pgr record -p 1234 -l
# Record every 5 seconds
pgr record -p 1234 -i 5s
Stop recording with Ctrl-C (SIGINT) or SIGTERM. Recording also stops automatically when the root process exits.
Output is JSON Lines — one JSON object per line, one line per sample. Each sample contains a timestamp and resource stats for every process in the tree at that point in time:
{
"timestamp": "2026-05-15T10:30:00.123Z",
"processes": [
{
"pid": 1234,
"ppid": 1233,
"name": "myapp",
"vm_size_kb": 67890,
"vm_rss_kb": 12345,
"shared_kb": 1000,
"swap_kb": 0,
"utime_ticks": 500,
"stime_ticks": 200,
"read_bytes": 4096000,
"write_bytes": 2048000,
"threads": 4,
"fd_count": 12
}
]
}| Field | Source | Description |
|---|---|---|
vm_size_kb |
/proc/[pid]/status |
Virtual memory size (kB) |
vm_rss_kb |
/proc/[pid]/status |
Resident set size — physical memory (kB) |
shared_kb |
/proc/[pid]/status |
Shared memory / RssShmem (kB) |
swap_kb |
/proc/[pid]/status |
Swapped memory (kB) |
utime_ticks |
/proc/[pid]/stat |
CPU time spent in user mode (clock ticks) |
stime_ticks |
/proc/[pid]/stat |
CPU time spent in kernel mode (clock ticks) |
read_bytes |
/proc/[pid]/io |
Bytes read from storage |
write_bytes |
/proc/[pid]/io |
Bytes written to storage |
threads |
/proc/[pid]/status |
Number of threads |
fd_count |
/proc/[pid]/fd/ |
Number of open file descriptors |
Note: /proc/[pid]/io requires the reader to be the same user as the
process (or have CAP_SYS_PTRACE). If unreadable, read_bytes and
write_bytes will be 0.
Render a recording as a terminal line chart:
pgr draw <file>
pgr draw - # read from stdin (live mode)
Options:
| Flag | Short | Default | Description |
|---|---|---|---|
--metric |
-m |
rss |
Metric to plot (see below) |
--no-total |
false |
Hide the aggregate total line | |
--no-per-process |
false |
Hide individual process lines | |
--height |
-H |
auto | Chart height in terminal rows |
--human-readable |
-r |
false |
Show y-axis values in human-readable format |
--top |
-n |
0 (all) | Show only the top N processes by peak usage |
--group |
-g |
false |
Group processes by name (sum values for same-name PIDs) |
--timespan |
-t |
0 (all) | Only show the last duration of data (e.g. 30s, 5m) |
Examples:
# Draw RSS chart from a file
pgr draw recording.jsonl
# Live chart piped from record
pgr record -p 1234 | pgr draw -
# CPU ticks chart with human-readable axis, top 5 processes
pgr draw recording.jsonl -m cpu -r -n 5
# I/O bytes chart, grouped by process name
pgr draw recording.jsonl -m io -r -g
# Thread count over time
pgr draw recording.jsonl -m threads
# Only the last 2 minutes
pgr draw recording.jsonl -t 2m
Render a summary table of process tree resource usage:
pgr table <file>
pgr table - # read from stdin (live mode)
Options:
| Flag | Short | Default | Description |
|---|---|---|---|
--metric |
-m |
rss |
Metric to display (see below) |
--human-readable |
-r |
false |
Show values in human-readable format |
--top |
-n |
0 (all) | Show only the top N processes by peak usage |
--group |
-g |
false |
Group processes by name (sum values for same-name PIDs) |
The table shows each process with its runtime, average, and peak value for the selected metric. In the default (non-grouped) mode, processes are displayed as a tree reflecting the parent-child hierarchy.
Examples:
# RSS table from a file
pgr table recording.jsonl
# Human-readable memory table, top 10
pgr table recording.jsonl -r -n 10
# Thread count table grouped by name
pgr table recording.jsonl -m threads -g
# FD count table
pgr table recording.jsonl -m fds -r
# Live table piped from record
pgr record -p 1234 | pgr table -
| Name | Description | Unit |
|---|---|---|
rss |
Resident set size (default) | kB |
vmsize |
Virtual memory size | kB |
shared |
Shared memory | kB |
swap |
Swap usage | kB |
cpu |
Total CPU time (user + system) | ticks |
utime |
User-mode CPU time | ticks |
stime |
System-mode CPU time | ticks |
io |
Total I/O (read + write) | bytes |
read_bytes |
Storage bytes read | bytes |
write_bytes |
Storage bytes written | bytes |
threads |
Thread count | count |
fds |
Open file descriptor count | count |
An unknown --metric value will produce an error.
In live mode (draw -), when --timespan is set, old samples outside the
window are discarded to keep memory usage bounded.
pgr version
Pass version and commit at build time via ldflags:
go build -ldflags "-X main.version=1.0.0 -X main.commit=$(git rev-parse --short HEAD)" ./cmd/pgr
See LICENSE.