Real-time system monitor for the gardesk desktop
gartop is a daemon-based system monitor featuring real-time graphs for CPU, memory, network, and disk I/O. It includes an interactive process list with tree view, sorting, search, and kill functionality, plus automatic container detection for Docker, Podman, and Kubernetes. Built on gartk with a Catppuccin-themed interface and per-process network socket tracking.
| Key | Action |
|---|---|
Tab | Cycle to next tab (CPU β Memory β Network β Disk) |
1 / 2 / 3 / 4 | Jump to CPU / Memory / Network / Disk tab |
Up / k | Move selection up in process list |
Down / j | Move selection down in process list |
Page Up | Page up in process list |
Page Down | Page down in process list |
Home / g | Jump to first process |
End / G | Jump to last process |
f | Freeze/unfreeze updates (for manual navigation) |
t | Toggle tree view (process hierarchy) |
/ or s | Search/filter processes by name |
k | Kill selected process (sends SIGTERM) |
K | Force kill selected process (sends SIGKILL) |
h / ? | Show help overlay |
q / Escape | Quit (or clear search) |
Time-series visualization with 5-minute history. Line graphs with optional fill, configurable grid lines, legend, and auto-scaled Y-axis.
Tree view with parent-child hierarchy, 10 sort modes, search filter, freeze mode for navigation, and kill with SIGTERM/SIGKILL.
Socket tracking via netlink INET_DIAG. TCP/UDP counts, listen/established states, and bandwidth rates per process.
Automatic identification of Docker, Podman, Kubernetes, and LXC containers via cgroup path parsing.
Temperature sensors from /sys/class/hwmon. GPU utilization, VRAM, clock speed, and power usage for AMD DRM devices.
JSON protocol over Unix socket. gartopctl for scripted queries, garbar integration, and real-time event subscription.
| Option | Type | Default | Description |
|---|---|---|---|
gartop | subcommand | gui | Launch GUI (starts daemon if needed) |
gartop gui | subcommand | - | Explicitly start GUI mode |
gartop daemon | subcommand | - | Run as background daemon |
--pane | string | "cpu" | Initial pane: cpu, memory, network, disk |
--config | path | ~/.config/gartop/config.toml | Configuration file path |
--foreground | flag | false | Run daemon in foreground (for debugging) |
gartop is configured via TOML at ~/.config/gartop/config.toml.
Custom path via --config flag.
# ~/.config/gartop/config.toml
[daemon]
# Data collection interval in milliseconds
sample_interval_ms = 1000
# Number of samples to keep in history
# At 1000ms = 5 minutes of history
history_size = 300
# Maximum processes to track (sorted by CPU)
max_processes = 100
[gui]
# Initial window dimensions
width = 600
height = 500
# GUI refresh rate in FPS
refresh_rate = 30
# Show legend on graphs
show_legend = true
# Font settings
font_family = "sans-serif"
font_size = 12.0
# Initial tab: cpu, memory, network, disk
# Omit to open to CPU tab
default_pane = "cpu" | Option | Type | Default | Description |
|---|---|---|---|
sample_interval_ms | u64 | 1000 | Data collection interval in milliseconds |
history_size | usize | 300 | Number of samples to keep (5 min at 1Hz) |
max_processes | usize | 100 | Maximum number of processes to track |
| Option | Type | Default | Description |
|---|---|---|---|
width | u32 | 600 | Initial window width in pixels |
height | u32 | 500 | Initial window height in pixels |
refresh_rate | u32 | 30 | GUI refresh rate in FPS |
show_legend | bool | true | Show legend on graphs |
font_family | string | "sans-serif" | Font family for UI text |
font_size | f64 | 12.0 | Font size in points |
default_pane | string? | none | Initial tab: cpu, memory, network, disk |
Run gartop daemon as a user service for automatic startup:
# ~/.config/systemd/user/gartop.service
[Unit]
Description=gartop system monitor daemon
After=graphical-session.target
PartOf=graphical-session.target
[Service]
Type=simple
ExecStart=/usr/local/bin/gartop daemon
Restart=on-failure
RestartSec=3s
[Install]
WantedBy=graphical-session.target gartop is a system monitor designed for the gardesk desktop, providing real-time visualization of system resources. It uses a daemon/GUI split architecture where a background process continuously collects metrics and the GUI connects via IPC for visualization.
The daemon maintains ring buffers of historical data (default 300 samples = 5 minutes), while the GUI renders graphs and process lists at a configurable refresh rate. Multiple GUI windows can connect to the same daemon.
The daemon (gartop daemon) runs as a background process,
listening on a Unix socket at $XDG_RUNTIME_DIR/gartop.sock.
The GUI (gartop or gartop gui)
connects to the running daemon and renders the interface:
The daemon runs two collection loops:
Primary Loop (sample_interval_ms, default 1s):
ββ CPU Collector β reads /proc/stat
ββ Memory Collector β reads /proc/meminfo
ββ Network Collector β reads /proc/net/dev
ββ Disk Collector β reads /proc/diskstats
Secondary Loop (2Γ sample_interval_ms, default 2s):
ββ Process Collector β reads /proc/[pid]/*
ββ Calculates CPU % from jiffy deltas
ββ Reads I/O stats from /proc/[pid]/io
ββ Correlates sockets via inode mapping
ββ Detects containers from cgroup paths Temperature and GPU metrics are collected on-demand when requested via IPC.
Each metric type has a dedicated collector that reads from Linux kernel interfaces.
Source: /proc/stat
Reads kernel CPU times (user, nice, system, idle, iowait, irq, softirq, steal) and calculates usage percentage from deltas between samples:
active = user + nice + system + irq + softirq + steal
total = active + idle + iowait
usage_percent = (active_delta / total_delta) Γ 100 Data tracked: usage_percent (0-100), per_core array, core_count, timestamp
Source: /proc/meminfo
Uses MemAvailable (kernel 3.14+) for accurate available memory calculation:
used = total - available
swap_used = swap_total - swap_free
usage_percent = (used / total) Γ 100 Data tracked: total, used, free, available, swap_total, swap_used, usage_percent
Source: /proc/net/dev
Parses interface statistics and calculates rates from byte deltas. Automatically filters out:
Per-interface data: interface name, rx/tx_bytes, rx/tx_packets, rx/tx_rate (bytes/sec)
Source: /proc/diskstats
Reads sector counts and converts to bytes (512 bytes/sector). Filters to physical disks only:
Per-device data: device name, read/write_bytes, reads/writes, read/write_rate
Source: /sys/class/hwmon/
Scans all hwmon devices and reads temperature sensors:
temp*_input - Temperature in millidegrees Γ· 1000temp*_label - Human-readable name (Core 0, Package, etc.)temp*_crit - Critical thresholdtemp*_max - High thresholdPer-sensor data: label, device, temp_celsius, critical, high
Source: /sys/class/drm/
Scans DRM card* entries (not renderD*) and reads GPU metrics from sysfs/hwmon:
Source: /proc/[pid]/
Iterates all processes and collects comprehensive per-process statistics:
Sources: /proc/net/tcp*,
/proc/net/udp*, netlink INET_DIAG
The socket collector uses a two-phase approach for per-process network stats:
Per-process network data: net_connections, net_tcp, net_udp, net_listen, net_established, net_rx_rate, net_tx_rate
Four main tabs, each with dedicated graph and details:
Line graphs with optional fill under curve. Features:
Color scheme (Catppuccin): CPU pink (#f38ba8), Memory green (#a6e3a1), Swap yellow (#f9e2af), Network teal (#94e2d5), Disk mauve (#cba6f7)
Scrollable process table with rich features:
Toggle with t to show process hierarchy:
56px header showing key metrics at a glance:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β gartop CPU 15% β MEM 42% β NET β1.2M β500K β DSK ...β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Also shows max temperature and GPU utilization when available.
gartop detects containerized processes by parsing /proc/[pid]/cgroup:
| Runtime | Cgroup Pattern | Display Format |
|---|---|---|
| Docker | /docker/{id} | docker:a1b2c3d4e5f6 |
| Podman | /libpod-{id}.scope | podman:7f8g9h0i1j2k |
| Kubernetes | /kubepods/... | k8s:pod123abc |
| LXC | /lxc/{name} | lxc:mycontainer |
Container ID is shown in the process list when detected (first 12 characters).
gartop uses a Catppuccin Mocha-inspired color scheme:
Collected from /proc/stat:
{
"usage_percent": 45.2,
"per_core": [20.5, 60.1, 30.3, 50.8],
"core_count": 4,
"timestamp": 1707000000000
}
Collected from /proc/meminfo:
{
"total": 16000000000,
"used": 8000000000,
"free": 2000000000,
"available": 6000000000,
"swap_total": 4000000000,
"swap_used": 500000000,
"usage_percent": 50.0,
"timestamp": 1707000000000
}
Per-interface statistics from /proc/net/dev:
[
{
"interface": "eth0",
"rx_bytes": 1000000,
"tx_bytes": 500000,
"rx_packets": 5000,
"tx_packets": 2500,
"rx_rate": 10000.0,
"tx_rate": 5000.0,
"timestamp": 1707000000000
}
]
Per-device statistics from /proc/diskstats:
[
{
"device": "sda",
"read_bytes": 10000000,
"write_bytes": 5000000,
"reads": 1000,
"writes": 500,
"read_rate": 100000.0,
"write_rate": 50000.0,
"timestamp": 1707000000000
}
]
From /sys/class/hwmon/:
{
"sensors": [
{
"label": "Core 0",
"device": "coretemp",
"temp_celsius": 55.2,
"critical": 100.0,
"high": 80.0
}
],
"timestamp": 1707000000000
}
From /sys/class/drm/ (AMD):
{
"devices": [
{
"name": "card0",
"model": "amdgpu",
"usage_percent": 30.5,
"vram_used": 2000000000,
"vram_total": 4000000000,
"clock_mhz": 1500,
"temp_celsius": 65.0,
"power_watts": 150.0
}
],
"timestamp": 1707000000000
}
Per-process statistics from /proc/[pid]/:
{
"pid": 1234,
"ppid": 1,
"name": "firefox",
"cmdline": "/usr/bin/firefox --new-window",
"cpu_percent": 25.5,
"memory_percent": 10.2,
"rss": 1000000000,
"vsize": 2000000000,
"io_read_bytes": 500000000,
"io_write_bytes": 100000000,
"io_read_rate": 50000.0,
"io_write_rate": 10000.0,
"net_connections": 15,
"net_tcp": 12,
"net_udp": 3,
"net_listen": 0,
"net_established": 10,
"net_rx_rate": 100000.0,
"net_tx_rate": 50000.0,
"state": "sleeping",
"user": "user",
"container": "docker:a1b2c3d4e5f6"
} The daemon listens on a Unix socket for JSON commands:
$XDG_RUNTIME_DIR/gartop.sock or /tmp/gartop.sock| Command | Parameters | Description |
|---|---|---|
status | none | Get daemon status (version, uptime, sample interval) |
get_cpu | none | Get current CPU statistics |
get_cpu_history | count? | Get CPU usage history (optional count) |
get_memory | none | Get current memory statistics |
get_memory_history | count? | Get memory usage history |
get_network | none | Get per-interface network statistics |
get_network_history | count? | Get network history |
get_disk | none | Get per-device disk statistics |
get_disk_history | count? | Get disk history |
get_temperature | none | Get all temperature sensors |
get_gpu | none | Get GPU statistics |
get_processes | sort_by?, limit? | Get sorted process list |
kill_process | pid, signal? | Kill process (default: SIGTERM) |
subscribe | events[] | Subscribe to real-time updates |
unsubscribe | events[] | Unsubscribe from events |
reload | none | Reload daemon configuration |
quit | none | Stop the daemon |
| Sort Field | Description |
|---|---|
cpu | Sort by CPU usage (default) |
memory | Sort by memory usage |
pid | Sort by process ID |
name | Sort alphabetically by name |
disk_read | Sort by disk read rate |
disk_write | Sort by disk write rate |
disk_total | Sort by total disk I/O |
net_connections | Sort by network connections |
net_tcp | Sort by TCP connections |
net_bandwidth | Sort by network bandwidth |
Subscribe to real-time metric updates:
# Subscribe command
{"command": "subscribe", "events": ["cpu_update", "memory_update"]}
# Streaming responses (one per line)
{"event": "cpu_update", "usage_percent": 45.2, ...}
{"event": "memory_update", "usage_percent": 50.0, ...} Configure garbar module clicks to open gartop:
-- ~/.config/gar/init.lua
gar.bar.modules = {
{
type = "cpu",
on_click = "gartop --pane cpu",
},
{
type = "memory",
on_click = "gartop --pane memory",
},
{
type = "battery",
-- Show CPU+memory when clicking battery (power consumption)
on_click = "gartop --pane cpu",
},
} The daemon must be running before the GUI can connect:
Temperature sensors require kernel modules and lm_sensors:
Reading /proc/[pid]/io requires elevated permissions:
Alternatively, run the daemon as root (not recommended for general use).
GPU monitoring requires DRM device access:
Per-process network stats use netlink, which may require permissions:
Enable verbose logging for troubleshooting:
If gartop itself uses too much CPU:
# Increase sample interval
[daemon]
sample_interval_ms = 2000 # 2 seconds instead of 1
# Reduce max processes tracked
max_processes = 50
# Lower GUI refresh rate
[gui]
refresh_rate = 15 # 15 FPS instead of 30