Skip to content
UtkarshJoshiNtlPublic

About

System Performance Dashboard TUI

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

48 Commits

Folders and files

Repository files navigation

Visage v0.2.0 — System Performance Dashboard

CI

A live terminal UI that puts your system's vital metrics at your fingertips. Built for developers who want to understand what their machine is doing, in real time.

┌──────────────────────────────────────────────────────┐
│  Visage                                    Ctrl+Q  │
│                                                       │
│  CPU — AMD Ryzen 9 5950X                              │
│  ████████████████████████░░░░░░░  83%                 │
│  4.8 GHz   Uptime: 14d 3h   Ctx: 1.2M/s             │
│                                                       │
│  Memory                                               │
│  ██████████████████░░░░░░░░░░░  6.3 / 15.5 GB        │
│                                                       │
│  Network                                              │
│  ↓ 18.2 Mb/s  ↑ 2.1 Mb/s   ↓ 120 GB  ↑ 45 GB       │
│  eth0  192.168.1.42  ↓18.2Mb/s  ↑2.1Mb/s            │
│                                                       │
│  Disk                                                 │
│  Read: 45.2 MB/s  Write: 12.8 MB/s                   │
│                                                       │
│  GPU — NVIDIA RTX 4090                               │
│  ████████████████████░░░░░░░  78% SM  65% MEM        │
│  2.4 GHz  350W  65°C                                  │
│                                                       │
│  Processes                                            │
│  Name                  PID    CPU%   Mem%    RSS      │
│  ▶ firefox             1234   12.3    8.1   1.2 GB   │
│    python3             5678    8.7    4.2   680 MB   │
│    clang              12345    5.1    2.8   450 MB   │
│                                                       │
│  q:Quit r:Refresh +:Faster -:Slower g:GPU             │
└──────────────────────────────────────────────────────┘

Quick Start

# Install from PyPI
pip install visage

# Or install from source
git clone https://github.com/UtkarshJoshiNtl/Visage
cd visage
pip install -e .

# Run the benchmark suite
visage

# Or launch the live dashboard
visage watch

Usage

Visage is command-based: benchmark is the default action, and the live dashboard moved to visage watch.

Watch Mode (visage watch)

Shows live metrics in a terminal UI with a single-screen grid layout:

Section Shows
CPU Total usage bar, per-core mini-graphs, model name, frequency, uptime, context switches
Memory RAM bar with used/total, swap usage (compact display)
Network Per-interface download/upload rates with IP addresses, cumulative totals
Disk Per-partition read/write rates (compact display)
GPU Multi-GPU array support, SM/memory utilization, clocks, power, temperature, PCIe bandwidth, roofline analysis, sparkline graphs
Processes Top processes with AI framework tagging (vLLM, PyTorch, Ollama, etc.), sort, tree view, aggregate mode, filtering

Controls

Key Action
q Quit
r Force refresh all metrics
+ Increase refresh speed (5s → 2s → 1s → 0.5s)
- Decrease refresh speed (0.5s → 1s → 2s → 5s)
t Cycle color themes
g Cycle active GPU in multi-GPU setups

Benchmark Mode (default)

visage                # full suite: CPU + memory + disk
visage benchmark cpu  # single test: cpu | memory | disk

Runs three performance tests inline and prints scored results:

  • CPU — Leibniz pi approximation (iterations/second)
  • Memory — Sequential read/write bandwidth (MB/s)
  • Disk — Sequential write/read on a temp file (MB/s)

Hardware-Isolated Benchmark Runner

Programmatic entry points for deterministic, noise-filtered benchmarking:

from visage.runners import run_isolated, run_benchmark

# Single run on core 3 with PMU counters
r = run_isolated("/usr/bin/myapp", core_id=3)

# Repeated runs with statistical noise filtering
s = run_benchmark("/usr/bin/myapp", core_id=3,
                  iterations=10, max_sigma_pct=1.0)
print(f"IPC: μ={s.ipc_mean:.3f} σ={s.ipc_std:.3f} noisy={s.noisy}")

Features:

  • Core isolation — cpuset cgroup v2 (root) → sched_setaffinity fallback
  • Frequency lock — saves governor + min/max freq, sets performance governor at a constant kHz
  • Hardware PMU counters — perf_event_open via raw ctypes (cycles, instructions, cache misses, IPC)
  • Noise filtering — runs N iterations, computes μ and σ, flags if any CV exceeds threshold

All features degrade gracefully when unprivileged (WSL2, no root).

CI/CD Performance Regression Gatekeeper

Visage acts as a deterministic performance gatekeeper in automated CI/CD workflows:

# Basic performance assertion on dedicated core 3
visage ci-gate ./build/my_engine --core 3 --iterations 10 --max-cv 2.0

# Compare against saved baseline with max allowed regressions
visage ci-gate ./build/my_engine \
  --baseline ./benchmarks/baseline.json \
  --max-ipc-drop 5.0 \
  --max-time-increase 5.0 \
  --output-md ./github_summary.md \
  --output-json ./ci_report.json

# Save current run as new baseline
visage ci-gate ./build/my_engine --save-baseline ./benchmarks/baseline.json

# Pass arguments to the benchmarked executable (after --)
visage ci-gate ./build/my_engine -- --threads 4

Outputs GitHub Actions Markdown summaries with silicon IPC, LLC cache misses, and statistical confidence intervals, exiting 0 on success and 1 on regression.

Themes

Press t to cycle through 6 built-in themes:

Theme Style
Tokyo Night Default — dark blue with cyan accents
Dracula Purple accents on dark gray
Gruvbox Retro warm colors with yellow accents
Nord Arctic blue palette
Monokai Vibrant colors on dark background
Solarized Precision colors for machines and people

Custom themes can be loaded from TOML files:

{
  "theme": "dracula"
}

Or create your own theme file:

[meta]
display_name = "My Theme"
graph_style = "braille"

[colors]
bg = "#1a1b26"
card = "#24283b"
border = "#3b4261"
accent = "#7aa2f7"
text = "#a9b1d6"
graph = "#7dcfff"
dim = "#565f89"

Configuration

Visage reads config from (in order of priority):

  1. visage.json in the current directory
  2. ~/.config/visage/config.json
  3. ~/.visage.json

Every key is optional; defaults apply for anything omitted. thresholds entries merge per-metric with the built-in defaults, so overriding cpu.red keeps the default cpu.yellow.

{
  "refresh": { "interval": 1.0 },
  "theme": "default",
  "graph_style": "braille",
  "widgets": {
    "enabled": ["cpu", "memory", "disk", "network", "gpu", "psi", "sensors", "battery", "docker", "processes"],
    "order": ["cpu", "memory", "disk", "network", "gpu", "psi", "sensors", "battery", "docker", "processes"]
  },
  "thresholds": {
    "cpu":     { "red": 80, "yellow": 50 },
    "memory":  { "red": 90, "yellow": 75 },
    "gpu_sm_util":   { "red": 80, "yellow": 50 },
    "gpu_mem_util":  { "red": 80, "yellow": 50 },
    "gpu_temp_c":    { "red": 85, "yellow": 70 },
    "gpu_power_w":   { "red": 90, "yellow": 75 }
  },
  "gpu": { "arch_override": null },
  "alerts": [
    { "name": "cpu-hot", "metric": "cpu_percent", "op": "gt",
      "value": 80, "cooldown": 60, "message": "CPU at {value}%" }
  ]
}
Option Type Default Description
refresh.interval float 1.0 Dashboard refresh interval in seconds
theme string "default" Built-in theme name or path to custom TOML theme
graph_style string "braille" Graph rendering: "braille", "block", "ascii", or "auto"
widgets.enabled list all Which sections to show
widgets.order list default Display order of sections
thresholds dict see above Color thresholds for utilization bars
gpu.arch_override string null Force GPU architecture detection
alerts list [] Alert rules (see below)

Alert rules: op is one of gt|lt|gte|lte, cooldown (seconds) suppresses repeats.

Remote Monitoring

visage serve
visage serve --remote-port 9090  # custom port
visage serve --remote-host 0.0.0.0  # bind to all interfaces (default: 127.0.0.1)

Exposes all metrics as JSON over HTTP, with per-metric endpoints and WebSocket streaming. By default, binds to 127.0.0.1 (localhost only). Set VISAGE_AUTH_TOKEN in the environment to enable Bearer token authentication on all endpoints.

curl http://localhost:8090/metrics
curl http://localhost:8090/cpu
curl http://localhost:8090/memory
curl http://localhost:8090/gpu

Prometheus-compatible metrics:

curl http://localhost:8090/metrics/prometheus
# → visage_cpu_percent 42.5
# → visage_memory_percent 63.2
# → visage_memory_used 10240000000

WebSocket for real-time streaming:

wscat -c ws://localhost:8090/ws/metrics

Environment Variables:

Variable Default Description
VISAGE_AUTH_TOKEN (none) If set, all endpoints require Authorization: Bearer <token>
VISAGE_CORS_ORIGINS http://localhost,... Comma-separated allowed origins for CORS

Notes:

  • All endpoints serve a cached system snapshot with a 1-second TTL. Concurrent clients share a single collection pass instead of triggering one each, so responses can lag live values by up to a second.
  • The WebSocket stream pushes a fresh snapshot every 2 seconds.
  • Binding to a non-loopback address without VISAGE_AUTH_TOKEN prints a warning at startup — process command lines and usernames would be exposed unauthenticated.

Endpoints:

Route Description
GET / Service info and version
GET /metrics Full system snapshot (all metrics)
GET /metrics/prometheus Prometheus exposition format
GET /cpu CPU metrics only
GET /memory Memory metrics only
GET /disk Disk metrics only
GET /network Network metrics only
GET /gpu GPU metrics only
GET /processes Process list
GET /sensors Temperature, fans, and power
GET /battery Battery status
GET /health Health check
WS /ws/metrics Real-time streaming (CPU, memory, disk, network, processes)

Export

# JSON snapshot (default)
visage export
visage export --output /tmp/metrics.json

# JSON Lines format (append-friendly, one JSON object per line)
visage export --format jsonl --output metrics.jsonl

Writes a one-shot snapshot of all metrics to a file (ISO timestamped).

Continuous Export

visage export --continuous --interval 5 --output metrics.csv

Writes metrics to CSV at regular intervals. Ctrl+C to stop.

If the output file already exists, rows are appended and the existing header line is reused — a schema change between runs drops unknown columns and pads missing ones instead of misaligning the file.

Shell Completions

Shell completions are available in completions/:

# Bash — add to ~/.bashrc
source /path/to/visage/completions/visage.bash

# Zsh — add to ~/.zshrc
source /path/to/visage/completions/visage.zsh

# Fish — copy to completions directory
cp completions/visage.fish ~/.config/fish/completions/

Man Page

man ./visage.1

CLI Reference

visage                       Run the benchmark suite (default action)
visage benchmark [preset]    Run benchmarks: cpu | memory | disk | all
visage watch [--config PATH] Launch the live TUI dashboard
visage serve                 Start the remote monitoring HTTP server
  --remote-host HOST           Bind address (default: 127.0.0.1)
  --remote-port PORT           Port (default: 8090)
visage export                Snapshot metrics to a file
  [--continuous]               Append CSV rows at intervals instead
  --format {json,jsonl}        Snapshot format (default: json)
  --interval SECS              Interval for --continuous (default: 5.0)
  --output PATH                Output path (default: ~/visage_snapshot.json)
visage ci-gate EXECUTABLE    Hardware-isolated CI performance gate
  [ARGS after --]              Passed to EXECUTABLE
  --core N                     Target CPU core index (default: 0)
  --iterations N               Iterations for benchmarking (default: 10)
  --max-cv PCT                 Max allowable noise CV percentage (default: 2.0)
  --min-ipc IPC                Minimum required IPC assertion
  --max-time SECS              Maximum allowed mean wall time in seconds
  --max-ipc-drop PCT           Max allowed IPC drop percentage under baseline
  --max-time-increase PCT      Max allowed wall time increase over baseline
  --max-miss-increase PCT      Max allowed cache miss increase over baseline
  --baseline PATH              Path to baseline benchmark JSON file
  --save-baseline PATH         Save current run as baseline JSON
  --output-md PATH             Write GitHub Actions markdown summary report
  --output-json PATH           Write JSON benchmark summary report
visage --version             Show version and exit

Legacy flags from earlier releases are still accepted and routed to their
subcommand: --benchmark, --remote, --export, --export-continuous,
--export-format, --export-interval, --ci-test, --test-args, --config.

Architecture

visage/
├── pyproject.toml              # Package metadata, dependencies, entry point
├── visage.1                    # Man page
├── completions/                # Shell completions (bash/zsh/fish)
│   ├── visage.bash
│   ├── visage.zsh
│   └── visage.fish
├── README.md
└── visage/
    ├── __init__.py
    ├── __main__.py             # CLI dispatcher (benchmark / watch / serve / export / ci-gate)
    ├── app.py                  # Textual Application, timer, data wiring, theme cycling
    ├── alert.py                # Rule-based alert engine (threshold checks, cooldowns)
    ├── config.py               # Zero-dependency JSON config loader
    ├── theme.py                # TOML theme engine, TCSS generation
    ├── style.tcss              # Tokyo Night inspired theme (CSS for TUI)
    ├── util.py                 # format_bytes, format_rate, DeltaTracker, sparklines, ASCII fallback
    ├── collectors/
    │   ├── cpu.py              # Raw /proc/stat parser (no psutil)
    │   ├── memory.py           # Raw /proc/meminfo parser (no psutil)
    │   ├── disk.py             # Cumulative disk I/O via psutil
    │   ├── network.py          # Cumulative net I/O + per-process network approximation
    │   ├── process.py          # psutil.process_iter, sort/tree/aggregate/filter
    │   ├── gpu.py              # NVIDIA (NVML) / AMD (AMDSMI) metrics, roofline data
    │   ├── perf.py             # Hardware PMU counters via perf_event_open + ctypes
    │   ├── sensors.py          # Temperatures, fan speeds (hwmon), RAPL power
    │   ├── psi.py              # Pressure Stall Information (CPU/memory/IO)
    │   ├── battery.py          # Battery status from sysfs
    │   ├── docker.py           # Container stats via docker CLI
    │   └── cache.py            # /proc/cpuinfo cache topology
    ├── widgets/
    │   ├── cpu.py              # ProgressBar + per-core sparkline
    │   ├── memory.py           # ProgressBar + used/total + swap
    │   ├── disk.py             # Read/write rates
    │   ├── network.py          # ↓↑ throughput + cumulative totals
    │   ├── gpu.py              # Utilization, clocks, power, roofline + bound-by
    │   ├── psi.py              # Pressure stall sparklines
    │   ├── sensors.py          # Temps, fans, power
    │   ├── battery.py          # Battery level bar
    │   ├── docker.py           # Container stats table
    │   └── processes.py        # Rich Table with sort/tree/aggregate/vim/filter/signals
    ├── themes/                  # Built-in TOML theme files
    │   ├── default.toml        # Tokyo Night
    │   ├── dracula.toml
    │   ├── gruvbox.toml
    │   ├── nord.toml
    │   ├── monokai.toml
    │   └── solarized.toml
    ├── benchmark/
    │   └── runner.py           # CPU pi, memory bandwidth, disk sequential
    ├── runners/
    │   ├── __init__.py         # Public API: run_isolated, run_benchmark
    │   └── isolated.py         # CpuCage, CpufreqLock, BenchmarkResult, BenchmarkSummary
    ├── tracing/
    │   ├── __init__.py         # create_tracer factory
    │   └── tracer.py           # BCC eBPF tracer + /proc polling fallback
    ├── export/
    │   └── exporter.py         # JSON / JSON Lines / CSV / log append / Prometheus format
    └── remote/
        └── server.py           # FastAPI app exposing /metrics + Prometheus endpoint

Design Decisions

  • Collectors are stateless — they return plain dicts. Stateful rate computation (disk, network deltas) lives in DeltaTracker in util.py, owned by the app layer. Deltas are divided by wall-clock time between ticks, so displayed rates stay correct when tick timing jitters.
  • Thread-safe collectors — cpu.py, memory.py, network.py use threading.Lock to protect FD access and state from concurrent reads.
  • Widgets use Textual reactives — each widget exposes reactive attributes and public read-only properties. Setting them triggers targeted re-renders.
  • Theme system is TOML-based — themes define color variables that generate TCSS dynamically. Cached to ~/.cache/visage/style.tcss. No external deps.
  • Per-process network is approximated — processes are grouped by network namespace (/proc/[pid]/ns/net); each namespace's /proc/[pid]/net/dev counters are read once and attributed across its member processes by CPU share, so estimates sum to actual interface traffic. The eBPF tracer takes precedence when available (root + BCC).
  • ASCII fallback is automatic — SSH sessions and non-UTF terminals get block/ASCII graphs instead of braille.
  • Remote mode is secure by default — binds to 127.0.0.1, restricts CORS to localhost, optional Bearer token auth, warns when binding non-loopback without a token, and bounds concurrent metric collections behind a shared 1-second snapshot cache.
  • Raw /proc parsers replace psutil for CPU and memory — single FD opened once, seek(0) each tick, with stale FD recovery.
  • No third-party deps for PMU counters — perf_event_open called via raw ctypes.
  • Graceful degradation — all kernel-level features (eBPF, PMU, cpuset, frequency lock) fall back to unprivileged alternatives when root/permissions are unavailable.

Requirements

  • Python ≥ 3.11
  • Linux (for full sensor, PMU, and cache support; macOS works with reduced features)

Dependencies (installed automatically):

Package Purpose
psutil System metrics (disk, network, processes; CPU & memory use raw /proc)
textual Terminal UI framework
rich Pretty terminal output (tables, formatting)
fastapi + uvicorn Remote monitoring web server (optional)
python3-bpfcc eBPF process tracer via BCC (optional, requires root)

Development

git clone https://github.com/UtkarshJoshiNtl/Visage
cd visage
pip install -e ".[dev]"
python -m pytest tests/ -v

Roadmap

  • Core dashboard (CPU, memory, disk, network, processes)
  • Benchmark mode
  • Process tracing (BCC eBPF + /proc fallback)
  • Temperature & power sensors
  • Cache statistics
  • JSON/CSV export
  • Remote monitoring via FastAPI
  • Hardware sandbox (core isolation + frequency lock + PMU counters + noise filtering)
  • GPU metrics (NVIDIA / AMD) with roofline analysis
  • Historical graphs (sparklines)
  • Config file (which metrics to show, thresholds) + alert rules
  • Docker support
  • Interactive process management (sort, tree, filter, detail, signals)
  • Per-disk and per-network interface breakdown
  • Battery monitor
  • Block graph rendering and per-core CPU mini-graphs
  • WebSocket streaming for remote monitoring
  • Continuous CSV export mode
  • Aggregate multi-process view, nice column, renice, vim mode, PgUp/PgDown
  • Fan speeds (hwmon), per-process network, cumulative network totals
  • Theme engine (TOML), 6 built-in themes, SSH/ASCII fallback
  • JSON Lines export, Prometheus endpoint, man page, tab completions, PyPI packaging
  • Thread-safe collectors (cpu, memory, network), remote server security hardening
  • Conditional widget timers, public widget properties, CSS fallback resilience
  • Stale FD recovery (cpu, memory), cross-platform perf counters, consistent battery API

License

MIT

About

System Performance Dashboard TUI

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages