`detect_in_process()` is for callers whose metered work runs on the CPU in
this process, and only for them. Each place eoc picks a counter was checked
against that:
- The `eoc` CLI's query cascade: adopted. Every stage it builds runs on the
CPU in this process: the LRU cache, the in-memory KV store, the in-memory
graph, and the echo backend, which formats a string. None spawns a
subprocess or offloads to the GPU, and they run on this process's tokio
workers. `build_cascade_with` now meters with `detect_in_process()`, and
its doc says a backend passed to it must keep to the same.
- `eoc meter` still reports `detect()`'s counter and its idle draw, and now
also names the counter `eoc query` meters with.
- Not adopted anywhere else, because no other eoc code picks a counter:
eoc-cascade and eoc-agent default to the stub and take the caller's;
eoc-streaming and eoc-local's backends take the caller's. eoc-agent must not
be given this one in any case: its tools include eoc-tools' shell, a
subprocess.
- eoc-local's crate doc now says which backends this counter covers. All four
run in this process, but `mlx` (GPU, Neural Engine), `mlc` (GPU),
`llamacpp` (GPU by default, `n_gpu_layers` 999) and `onnx` with a CoreML,
CUDA, DirectML or TensorRT provider offload work it does not see. It covers
`onnx` with the CPU provider and `llamacpp` with `n_gpu_layers` 0.
What the CLI reports on this M5 Max:
counter: powermetrics
query : metered by process-energy (its stages all run on the CPU in this process)
eoc query "what is 2+2" -> stage kv, cost 50 µJ (estimated)
eoc query "tell me something new" -> stage neural, cost 50000000 µJ (estimated)
Both lookups finish inside one update of the counter, so neither span
advanced and each stage's own figure stands, as eoc-cascade requires.
Tests. `work_on_an_unmetered_host_keeps_its_estimate` now expects the CLI's
meter to be `process-energy` exactly when it is live (and IOReport's rule
otherwise); its ~100 ms burn with a 50 J estimate costs the estimate plus the
reading, tagged estimated: "meter=process-energy cost=50230593 µJ
(estimated)" in one run. A new test, `in_process_work_is_measured_by_the_process_counter`,
runs ~100 ms of CPU work through the CLI cascade from a backend that claims
nothing (an estimated zero): it reads as measured, between 1 mJ and 10 J. The
floor is low on purpose, since a wall-time burn on a loaded host or an
efficiency core can draw little; the size of a reading is pinned in
eoc-meter's hardware test. Here: "eoc in-process cost: 273344 µJ (measured)"
and "meter=process-energy cost=50270761 µJ (estimated)". The two burning tests
take one lock, since each would otherwise read the other's burn: run in
parallel they read 380637 µJ each.
Co-Authored-By: Claude Opus 5.5 <[email protected]>