Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dev-Pulse

Apple Silicon telemetry for machine-learning workloads — it answers the question you actually have after a slow training run: what was holding it back?

Most system monitors show you a graph and leave the interpretation to you. Dev-Pulse lets you bracket a run, then tells you whether it was GPU-bound, CPU-bound, memory-bound, or waiting on I/O — with the evidence behind the verdict.

  finetune-resnet-v3  (session 4)
  bs=64, lr=3e-4
  Duration: 1840s

  Bottleneck: CPU  [confidence: high]
  CPU-bound: CPU averaged 94% while GPU averaged only 12%. The accelerator
  is being starved — time is going to data loading or preprocessing.

  Evidence
    cpu_mean             94.1
    gpu_mean             11.8
    ram_mean_percent     61.0
    p_core_mean          97.2
    e_core_mean          88.4

  Suggested next steps
    - Raise DataLoader worker count and enable prefetching.
    - Move augmentation off the hot path, or cache it.
    - Profile the input pipeline before touching the model.

Why this exists

Training on a laptop, the interesting failure is rarely "the model is wrong". It is that an expensive GPU sits at 12% while eight CPU cores thrash through JPEG decoding. That is invisible on a utilisation graph unless you know to look for the combination — high CPU, low GPU, at the same time.

Dev-Pulse records that combination and names it.

How it works

  cli.py start <label>          opens a workload session
        │
        ▼
  collector.py  ── samples ──▶  SQLite  ◀── reads ──  dashboard.py
        │                                                  │
   topology.py  (P/E core split, from sysctl)               │
   gpu.py       (powermetrics, degrades honestly)           │
        │                                                  ▼
        ▼                                          analysis.py
  cli.py stop                                   (bottleneck verdict)
Module Responsibility
devpulse/config.py Every tunable, overridable by environment variable
devpulse/topology.py Detects performance/efficiency core counts via sysctl
devpulse/gpu.py GPU residency via powermetrics; reports None when unavailable
devpulse/collector.py The sampling loop — batched writes, periodic pruning
devpulse/schema.py SQLAlchemy models, indexes, retention sweep
devpulse/workload.py Session lifecycle and analysis entry point
devpulse/analysis.py Bottleneck classification

Install

python -m venv venv && source venv/bin/activate
pip install -r requirements.txt

Use

Start the collector in one terminal — it runs until you stop it:

python cli.py collect

Bracket a run in another terminal:

python cli.py start finetune-resnet-v3 -n "bs=64, lr=3e-4"
# ... run your training ...
python cli.py stop
python cli.py report

Or from Python, which closes the session even if training raises:

from devpulse.workload import track

with track("finetune-resnet-v3", notes="bs=64"):
    train(model, loader)

Live dashboard:

streamlit run dashboard.py

GPU access

powermetrics requires root. Without it the GPU column reads n/a — deliberately, rather than a misleading 0%. Everything else still works.

To enable it, add a passwordless entry with sudo visudo:

your-username ALL=(root) NOPASSWD: /usr/bin/powermetrics

This grants passwordless root for powermetrics only. Skip it if you would rather not.

Configuration

Every value in devpulse/config.py reads an environment variable:

Variable Default Meaning
DEVPULSE_DB ./devpulse.db Database location
DEVPULSE_INTERVAL 1.0 Seconds between samples
DEVPULSE_COMMIT_EVERY 10 Samples buffered per commit
DEVPULSE_RETENTION_HOURS 72 Age at which untagged samples are pruned
DEVPULSE_GPU 1 Set 0 to skip GPU sampling entirely
DEVPULSE_GPU_BOUND 70.0 GPU % above which a run is GPU-bound
DEVPULSE_CPU_BOUND 70.0 CPU % above which a run is CPU-bound

Tests

pip install pytest && python -m pytest tests/ -q

Tests run against a temporary database and never touch collected telemetry.

Privacy

The database records the name of every process that crosses the CPU threshold — effectively a log of what you run. It is listed in .gitignore and is never committed. Delete it whenever you like; the schema is recreated on the next launch.

Changes

See CHANGELOG.md for the upgrade history, including the defects found in the first version and how each was fixed.

About

Apple Silicon telemetry for ML workloads — bracket a training run, get a bottleneck verdict (GPU / CPU / memory / IO-bound) with evidence.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages