# elphel-perfd — CPU+GPU performance management without sudo

Lets Eyesis/imagej-elphel (and any other local program) request deterministic
or maximum-performance clock states with **no sudo in the control path**.
Design ruled by Andrey 07/17/2026: the capability ships with imagej-elphel
because it follows the hardware the project runs on (224/137), while staying
usable by any program through the same local socket.

## Install (once per machine, the only sudo ever needed)

    sudo <imagej-elphel>/perfd/install.sh

Installs `/usr/local/lib/elphel-perfd/elphel_perfd.py`, the systemd unit
`elphel-perfd.service` (enabled, running as root), and the unprivileged
client `/usr/local/bin/perfctl`. Idempotent — re-run to update.

Eyesis checks for the daemon at startup: uses it when present, prints the
install command above when absent (and continues normally).

## Use

    perfctl status                     # clocks/holds one-liner
    perfctl hold measure -- <command>  # deterministic clocks for the command
    perfctl hold max                   # production profile until Ctrl-C

Profiles:
- `measure` — CPU frequency **pinned** (`scaling_min=max`, default 3.2 GHz,
  `PERFD_CPU_LOCK_KHZ`) + GPU persistence + GPU clocks **locked** (default
  2550 MHz, `PERFD_GPU_LOCK_MHZ`): run-to-run timing reproducibility (±1%
  instead of ±10% with free-running boost) for per-item performance
  evaluation. Pinned, not `performance`: the i9-11900K at free boost hits
  4.9 GHz → 100 °C → throttle wobble within seconds of an all-core phase
  (measured 07/17/2026) — boost bias is itself a nondeterminism source.
  Per-hold overrides: `perfctl hold measure cpu=3400000 gpu=2400 -- <cmd>`
  (bounds-checked; for calibration without reconfiguration).
- `max` — CPU `performance` profile (free boost) + GPU persistence, clocks
  unlocked: throughput.

A hold is tied to the client's connection — process exit or crash releases
it automatically (refcounted across concurrent holders; `measure` outranks
`max`). Daemon stop resets GPU clocks (`ExecStopPost=nvidia-smi -rgc`).

Protocol (127.0.0.1:48890, line-based): `PING`, `STATUS`, `HOLD measure|max`,
`RELEASE`, `QUIT`. Java client: `com.elphel.imagej.common.PerfDaemon`.

Supersedes `attic/elphel-agent-tools/bin/cpu_perf_hold.py` (CPU-only,
process-watch based) once installed.
