Posted on
Artificial Intelligence

Artificial Intelligence Performance Monitoring

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Artificial Intelligence Performance Monitoring on Linux: From Guesswork to Measurable Gains

AI workloads are expensive, opaque, and unforgiving. One minute your GPU looks idle, the next it’s thermal-throttling while your training loop crawls. If you can’t see what’s happening in real time, you can’t fix it. This post shows you how to monitor AI performance on Linux using battle-tested command-line tools and a bit of Bash, so you can find bottlenecks, prove improvements, and stop wasting GPU hours.

What you’ll get:

  • A practical, Linux-first toolkit for AI performance monitoring

  • 3–5 actionable steps to baseline, track, and optimize workloads

  • Real-world examples and scripts you can drop into your workflow

Why AI Performance Monitoring Is Non‑Optional

  • Bottlenecks hide in plain sight. Underutilized GPUs usually mean CPU, I/O, or data pipeline backpressure.

  • Cost control. Small utilization gains (e.g., 10–20%) compound to huge cloud savings over long training runs.

  • Reproducibility. Baseline metrics make performance regressions visible after code/data changes.

  • Capacity planning. Knowing throughput, latency, and resource headroom helps you scale responsibly.

Install the Toolbox

The tools below let you observe CPU, memory, GPU, disk, and end-to-end performance from the terminal. Install with your distro’s package manager.

Apt (Debian/Ubuntu):

sudo apt update
sudo apt install -y sysstat htop nvtop glances hyperfine jq numactl netdata

DNF (Fedora/RHEL/CentOS Stream):

sudo dnf install -y sysstat htop nvtop glances hyperfine jq numactl netdata

Zypper (openSUSE/SLE):

sudo zypper refresh
sudo zypper install -y sysstat htop nvtop glances hyperfine jq numactl netdata

Notes:

  • sysstat provides iostat, mpstat, pidstat.

  • nvtop requires working GPU drivers (NVIDIA: nvidia-smi available).

  • Optional service: Netdata web UI

    sudo systemctl enable --now netdata
    # Visit http://localhost:19999
    

Pick the Right AI KPIs

Measure what matters for your workload:

  • Throughput and latency: images/sec, tokens/sec, QPS, p50/p95 latency.

  • GPU health: utilization (SM), memory used, memory utilization, power draw, temperature.

  • CPU pressure: per-process %CPU, run queue length, context switches.

  • Memory: RSS per process, swap activity (should be zero under load).

  • I/O: disk util (%util), read/write IOPS and await; network throughput if remote storage.

  • Data loader and augmentation: time spent waiting for batches vs. compute.

  • Stability: variance over time (jitter), thermal throttling, OOM/evictions.

Step 1 — Baseline Quickly with One-Liners

Start with live visibility, then capture short windows to CSV or logs.

System and CPU:

htop
mpstat -P ALL 1
pidstat -dlru 1

Disk/IO bottlenecks:

iostat -xz 1

GPU live view (NVIDIA):

nvtop
nvidia-smi dmon -s pucvmt -i 0
# p=power, u=util, c=mem util, v=vid enc/dec, m=mem, t=temperature

Quick throughput/latency benchmarks:

hyperfine -w 3 -r 10 'python infer.py --batch 32' 'python infer.py --batch 64'

Lightweight system dashboard:

glances           # interactive TUI
glances -w        # web server at http://localhost:61208

Tip: capture a 2–5 minute sample while your workload is steady. You’re hunting for mismatch: high GPU idle time + high CPU or disk utilization usually means input pipeline starvation.

Step 2 — Automate Sampling with a Tiny Bash Logger

Use this drop-in script to log key metrics every second to CSV. It targets one process (PID) and one GPU (index 0 by default).

Save as ai-mon.sh:

#!/usr/bin/env bash
set -euo pipefail

PID="${1:-}"           # optional: target process ID (e.g., your python pid)
GPU="${GPU:-0}"        # select GPU index
INTERVAL="${INTERVAL:-1}"  # seconds

echo "ts,cpu_pct,mem_pct,mem_mb,gpu_util,gpu_mem_mb,gpu_mem_util,power_w"

while true; do
  TS=$(date +%s)

  if [[ -n "${PID}" ]]; then
    # %CPU, %MEM, RSS(KB)
    read -r CPU_P MEM_P RSS_KB < <(ps -p "$PID" -o %cpu,%mem,rss --no-headers | awk '{print $1" "$2" "$3}')
    [[ -z "${CPU_P:-}" ]] && { echo "Process $PID ended"; exit 0; }
    MEM_MB=$((RSS_KB/1024))
  else
    CPU_P=NA; MEM_P=NA; MEM_MB=NA
  fi

  # NVIDIA GPU metrics (requires nvidia-smi)
  if command -v nvidia-smi >/dev/null 2>&1; then
    IFS=, read -r GPU_UTIL GPU_MEM GPU_MEM_UTIL POWER < <(
      nvidia-smi --id="$GPU" \
        --query-gpu=utilization.gpu,memory.used,utilization.memory,power.draw \
        --format=csv,noheader,nounits | sed 's/ //g'
    )
  else
    GPU_UTIL=NA; GPU_MEM=NA; GPU_MEM_UTIL=NA; POWER=NA
  fi

  echo "$TS,$CPU_P,$MEM_P,$MEM_MB,$GPU_UTIL,$GPU_MEM,$GPU_MEM_UTIL,$POWER"
  sleep "$INTERVAL"
done

Usage:

chmod +x ai-mon.sh
# Start your workload, note its PID, then:
./ai-mon.sh <PID> > run.csv
# Or without PID for system-wide GPU logging:
./ai-mon.sh > run.csv

Open run.csv in your favorite tool to visualize. Look for:

  • GPU underutilized while CPU% or iostat %util is high → CPU/I/O bottleneck.

  • GPU mem util near 100% with low GPU util → batch size too big or fragmentation.

  • Power/thermals oscillating → consider power limits or better cooling.

Step 3 — Visualize and Watch Trends

If you prefer a no-config web dashboard:

sudo systemctl enable --now netdata
# http://localhost:19999 shows CPU, memory, disk, network, processes

Glances web mode is an even lighter option:

glances -w
# http://localhost:61208

For GPU specifics, keep a terminal with:

nvidia-smi dmon -s pucvmt -i 0

This combo covers long-running training and batch inference services with minimal setup.

Step 4 — Turn Insights into Speed

Once you see where time goes, apply fixes and validate with hyperfine or your CSV logs.

  • Data pipeline starvation

    • Increase data loader workers and prefetching.
    • Pre-decode/resize to reduce per-batch CPU load.
    • Keep datasets on local NVMe; watch iostat for queueing.
  • CPU/GPU affinity and NUMA

    numactl --cpunodebind=0 --membind=0 python train.py
    

    Pinning reduces cross-socket latency on multi-socket machines.

  • Mixed precision and larger batches (when memory allows)

    • Higher throughput with negligible accuracy loss in many models.
    • Validate gains: GPU util should rise, time/batch should fall.
  • Power and stability on NVIDIA

    sudo nvidia-smi -pm 1          # enable persistence mode
    sudo nvidia-smi -pl <watts>    # set safe, stable power limit (know your GPU!)
    

    Stable clocks and temps reduce jitter in latency-sensitive inference.

  • Concurrency tuning

    • For services, find the concurrency that saturates GPU without causing queue bloat (monitor p95 latency vs QPS).

Real-World Scenarios

  • Training throughput boost

    • Symptom: GPU util ~40%, CPU ~300% across 64 cores, iostat %util 5%.
    • Fix: Increase DataLoader workers from 4 to 16, enable pinned memory, move augmentations to GPU.
    • Result: GPU util 85–95%, images/sec +60%.
  • Inference jitter

    • Symptom: p95 latency spikes every few minutes, GPU util steady.
    • Fix: Limit power to avoid periodic thermal throttling, isolate CPU cores for the process with taskset/numactl.
    • Result: p95 stabilized, tail latency improved by 30–40%.
  • I/O bottleneck

    • Symptom: iostat shows %util ~95% on a single HDD, GPU idle bursts.
    • Fix: Stage data on NVMe and use sequential reads, cache hot shards.
    • Result: Smooth GPU utilization, run time -25%.

Quick Reference: Useful Commands

  • System CPU breakdown:

    mpstat -P ALL 1
    pidstat -dlru 1
    
  • Disk pressure:

    iostat -xz 1
    
  • GPU streams:

    nvidia-smi dmon -s pucvmt -i 0
    
  • Benchmark variations:

    hyperfine -w 3 -r 10 'python train.py --batch 64' 'python train.py --batch 96 --amp'
    

Conclusion and Next Steps

Most AI slowdowns aren’t on the GPU—they’re between your GPU and your data. With a few Linux tools and a small Bash logger, you can make bottlenecks obvious, apply targeted fixes, and verify real gains.

Your move: 1) Install the toolbox with your package manager. 2) Run a 5-minute baseline using the one-liners and ai-mon.sh. 3) Apply one optimization (data pipeline, batch size, NUMA pinning, or power tuning) and re-measure. 4) Keep the scripts in your repo so every run has a performance paper trail.

If you want a follow-up post on exporting these metrics to a full dashboard stack (e.g., Netdata deep-dive or Prometheus/Grafana), say the word.