feat(augaman): second, fixtures-only instance on fv-ml1 GPU 1; CPU vs GPU speed bench (v0.1.2 baseline)

Prime asked for augaman on fv-ml1's utility card, beside vllm-coder. Mirror
augaman-dev's f77164f compose, which parameterises the GPU reservation (GPU_ID,
default 0) and the Homepage card name (CARD_SUFFIX). esh-ml1's resolved config is
unchanged: same config hash, no recreate.

On fv-ml1: augaman:0.1.2 built on-box from the tag, GPU_ID=1, healthy on CUDA
at 1264 MiB, and pytest -m gpu tests/vision passes 3/3 on the Blackwell. It has
its own gallery and no gallery backup, so it is fixtures-only. The host's raw
restic copy of /var/lib/docker/volumes is not a consistent SQLite backup.

docs/pfi/augaman-speed-bench/ holds the harness (augaman-dev's recipe plus a
no-face control frame and a face-count check on every response), the raw rows
and the summary. Server-side, one face:
- esh-ml1 GPU 144 ms
- fv-ml1 GPU 75 ms
- fv-ml1 CPU on 6 cores 152 ms
- esh-ml1 CPU 888 ms
It agrees with augaman-dev's independent esh-ml1 measurement once each
harness's floor is subtracted. This is the before for v0.1.3's detector fix.
This commit is contained in:
vh
2026-09-27 00:28:20 -07:00
parent 2cd5048447
commit 317868dc7e
10 changed files with 774 additions and 10 deletions
+79
View File
@@ -0,0 +1,79 @@
# augaman speed bench: CPU vs esh-ml1 GPU vs fv-ml1 GPU
Asked by Prime on 2026-09-27. This is the **v0.1.2 "before"** baseline. v0.1.3 gives
each detector canvas its own ONNX session, removing the ~90 ms CUDA shape-switching
cost that comfy-dev found. The same harness is to be re-run on v0.1.3 for the "after".
## Harness (it is part of the number)
- **Client:** `bench.py` on nh3-dev, sequential. Each request uses a **fresh
connection** (no keep-alive) and is timed around the whole POST.
- **Protocol:** 3 runs. Per (target, frame, run) there are 3 warm-up requests,
then 20 timed ones. Runs are interleaved across targets and frames, so drift
spreads over every condition. Time: 0021–0026 PT, 2026-09-27.
- **Server-side column:** the change in `augaman_pipeline_seconds{op="probe"}`
sum/count over the 20 timed requests. It is decode + detect + embed with no
network or HTTP, and it is **the device comparison**. It is a mean, not a p50.
- **Floor:** a `/health` round trip, same client. It came out 28–34 ms, higher than
augaman-dev's 16 ms because of the fresh connection per request.
- **Frames** (`make_frames.py`): (a) 1920x1080 grey canvas with one face;
(b) `obama_biden_2015.jpg` as-is, 960x1001, two faces; **(c) the same 1080p grey
canvas with no face**, a detector-only control. Every response was checked for
the expected face count, and **0 of 900 were wrong**.
- **Images:** `augaman:0.1.2`, built from the same tag on each host (separate
builds, same source).
- **Targets:**
| target | device | notes |
|---|---|---|
| esh-ml1 GPU | RTX 2000E Ada 16 GB (50 W) | the production instance; shares the card with TEI + vllm-reward |
| fv-ml1 GPU1 | RTX PRO 6000 Blackwell Max-Q | the new second instance; shares GPU 1 with coder, erp and meromero seats |
| esh-ml1 CPU6 | the LXC's 6 host threads | throwaway `AUGAMAN_DEVICE=cpu` container. pve moved the LXC's cpuset between two reads, so it ran unpinned, with an affinity of 6 |
| fv-ml1 CPU6 | EPYC 9254, cpuset 0-5 | throwaway container; physical cores on socket 0 |
| fv-ml1 CPU24 | EPYC 9254, cpuset 0-23 | throwaway container; all physical cores of socket 0 |
GPU utilisation read 0% on fv-ml1 GPU 1 and 0–9% on esh-ml1 across the samples
(0020–0021, 3 samples each), so the co-resident seats were idle.
## Results (ms): median of the 3 run p50s, [min–max of the run p50s]
| target | (a) 1 face, e2e | (b) 2 faces, e2e | (c) no face, e2e | **server (a)** | **server (b)** | **server (c)** |
|---|---|---|---|---|---|---|
| esh-ml1 GPU | 196.5 [195.0–196.6] | 195.1 [194.0–196.1] | 181.0 [177.6–182.9] | **143.8** | **138.7** | **136.2** |
| fv-ml1 GPU1 | 126.6 [121.8–128.3] | 122.7 [122.4–127.9] | 109.2 [108.7–111.0] | **75.0** | **73.9** | **69.5** |
| esh-ml1 CPU6 | 954.6 [792.8–1023.3] | 1325.6 [1306.9–1327.6] | 205.1 [202.1–228.0] | **887.6** | **1253.4** | **159.4** |
| fv-ml1 CPU6 | 203.6 [203.5–204.5] | 222.5 [216.0–236.4] | 111.6 [110.6–112.7] | **152.4** | **179.4** | **72.3** |
| fv-ml1 CPU24 | 208.1 [204.6–221.6] | 223.7 [219.8–237.1] | 101.1 [100.5–113.4] | **155.9** | **167.3** | **61.9** |
The /health floor was 27.6–33.7 ms (median of run p50s) on every target. The raw
rows are in `rows-2026-09-27.json`, and `summarize.py` reproduces this table.
## What it says
- **fv-ml1's Blackwell is ~2× esh-ml1's Ada on v0.1.2:** 75 vs 144 ms server-side
for one face. End to end from nh3-dev it is 127 vs 197 ms.
- **On v0.1.2, a GPU buys little over a good CPU.** 6 EPYC cores do one face in
152 ms, as fast as esh-ml1's GPU (144 ms). With no face, fv-ml1's CPU (62–72 ms)
matches fv-ml1's GPU (70 ms). The GPU pipeline is dominated by something other
than GPU compute, and the cards read 0–9% utilisation while it ran. That is
consistent with the detector's shape-switching cost that v0.1.3 removes.
- **esh-ml1's CPU is not a viable home:** 0.9 s for one face and 1.3 s for two. Its
embedder costs ~730 ms per face, against ~80 ms on 6 EPYC cores. That gap is much
larger than the detector gap (159 vs 72 ms), and its runs were the noisiest
(793–1023 ms), so treat the esh CPU number as indicative. It was also sharing its 6
threads with TEI.
- **More EPYC threads do not help one frame:** CPU24 is roughly equal to CPU6 on faces.
## Controls and sensitivity
- **Repeats:** 3 runs × 20 per cell. The A-vs-A spread is the min–max above.
- **Noise floor:** the GPU cells spread by ≤6 ms across runs, and the fv CPU cells
by ≤20 ms. The esh-ml1 CPU (a) cell spread by 230 ms. Differences smaller than
those spreads are not findings.
- **Positive control (instrument agreement):** augaman-dev measured esh-ml1 (a)
independently at 186 ms with a 16 ms floor. This harness gets 196.5 ms with a
28 ms floor. Minus each floor, 170 vs 169 ms: they agree.
- **Positive control (detects work):** frame (c) is fastest on every target, and
the gap from (a) to (c) is the embedding cost. It is visible on every device.
- **Negative control:** the face count was checked on all 900 responses, and none
were wrong.
+70
View File
@@ -0,0 +1,70 @@
"""augaman /recognize latency bench, harness per augaman-dev (2026-09-27):
sequential from nh3-dev; per (target, frame, run): 3 warm-up requests, then 20 timed.
3 runs, interleaved across targets and frames so drift spreads over every condition.
Each request is a fresh connection (no keep-alive), timed around the whole POST.
Server-side share: delta of augaman_pipeline_seconds{op="probe"} sum/count over the
20 timed requests (a mean, not a p50). Every response is checked for the expected
face count; a mismatch invalidates the row. Floor: /health, 3 runs x 20, same client.
Targets come from BENCH_TARGETS as JSON [{name, url, token_env}]; tokens are read
from the environment and never printed.
"""
import json, os, re, sys, time
import httpx
FRAMES = [("a_1080p_1face", "frame_a_1080p_oneface.jpg", 1),
("b_960x1001_2face", "obama_biden_2015.jpg", 2),
("c_1080p_0face", "frame_c_1080p_noface.jpg", 0)]
RUNS, WARM, N = 3, 3, 20
targets = json.loads(os.environ["BENCH_TARGETS"])
data = {f: open(f, "rb").read() for _, f, _ in FRAMES}
PROBE = re.compile(r'^augaman_pipeline_seconds_(sum|count)\{[^}]*op="probe"[^}]*\}\s+([0-9.eE+-]+)$', re.M)
def probe_stats(url):
t = httpx.get(url + "/metrics", timeout=10).text
vals = {k: float(v) for k, v in PROBE.findall(t)}
return vals.get("sum", float("nan")), vals.get("count", float("nan"))
def recognize(url, tok, fname):
t0 = time.perf_counter()
r = httpx.post(url + "/recognize", headers={"Authorization": f"Bearer {tok}"},
files={"frame": (fname, data[fname], "image/jpeg")}, timeout=120)
dt = (time.perf_counter() - t0) * 1000
r.raise_for_status()
return dt, len(r.json()["faces"])
def pct(xs, p):
xs = sorted(xs); k = (len(xs) - 1) * p; f = int(k); c = min(f + 1, len(xs) - 1)
return xs[f] + (xs[c] - xs[f]) * (k - f)
rows = []
for run in range(1, RUNS + 1):
for t in targets:
url, tok = t["url"], os.environ[t["token_env"]]
# floor
h = []
for _ in range(N):
t0 = time.perf_counter(); httpx.get(url + "/health", timeout=10).raise_for_status()
h.append((time.perf_counter() - t0) * 1000)
rows.append({"target": t["name"], "frame": "health_floor", "run": run,
"p50": pct(h, .5), "p90": pct(h, .9), "server_probe_mean": None, "bad": 0})
for label, fname, want in FRAMES:
for _ in range(WARM):
recognize(url, tok, fname)
s0, c0 = probe_stats(url)
lat, bad = [], 0
for _ in range(N):
dt, faces = recognize(url, tok, fname)
lat.append(dt); bad += faces != want
s1, c1 = probe_stats(url)
srv = (s1 - s0) / (c1 - c0) * 1000 if c1 > c0 else None
rows.append({"target": t["name"], "frame": label, "run": run, "p50": pct(lat, .5),
"p90": pct(lat, .9), "server_probe_mean": srv, "bad": bad})
print(f"run{run} {t['name']:<16} {label:<17} p50 {pct(lat,.5):8.1f} p90 {pct(lat,.9):8.1f}"
f" srv {srv if srv is None else round(srv,1)} bad {bad}", flush=True)
json.dump(rows, open(sys.argv[1] if len(sys.argv) > 1 else "bench_rows.json", "w"), indent=1)
@@ -0,0 +1,14 @@
"""The bench frames, per augaman-dev's recipe (2026-09-27). Run in a directory holding
obama_2012.jpg and obama_biden_2015.jpg from pfi/augaman tests/fixtures/faces/ (public domain).
uv run --with pillow python make_frames.py
"""
from PIL import Image
o = Image.open("obama_2012.jpg").convert("RGB")
h = 700
o = o.resize((round(o.width * h / o.height), h), Image.LANCZOS)
a = Image.new("RGB", (1920, 1080), (90, 90, 90))
a.paste(o, (700, 190))
a.save("frame_a_1080p_oneface.jpg", quality=90) # (a) one face
Image.new("RGB", (1920, 1080), (90, 90, 90)).save("frame_c_1080p_noface.jpg", quality=90) # (c) control
# (b) is obama_biden_2015.jpg as-is: 960x1001, two faces
@@ -0,0 +1,542 @@
[
{
"target": "esh-ml1 GPU",
"frame": "health_floor",
"run": 1,
"p50": 28.755177503626328,
"p90": 35.665129897824954,
"server_probe_mean": null,
"bad": 0
},
{
"target": "esh-ml1 GPU",
"frame": "a_1080p_1face",
"run": 1,
"p50": 195.03028949839063,
"p90": 200.67508020147218,
"server_probe_mean": 143.80537764518522,
"bad": 0
},
{
"target": "esh-ml1 GPU",
"frame": "b_960x1001_2face",
"run": 1,
"p50": 195.12132549425587,
"p90": 208.15129229886224,
"server_probe_mean": 139.3810058987583,
"bad": 0
},
{
"target": "esh-ml1 GPU",
"frame": "c_1080p_0face",
"run": 1,
"p50": 182.8995855030371,
"p90": 191.65247399650985,
"server_probe_mean": 143.4166395556531,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "health_floor",
"run": 1,
"p50": 33.661384499282576,
"p90": 38.86325339844916,
"server_probe_mean": null,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "a_1080p_1face",
"run": 1,
"p50": 128.3326149932691,
"p90": 140.80376060592243,
"server_probe_mean": 74.98760224552825,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "b_960x1001_2face",
"run": 1,
"p50": 127.89153849735158,
"p90": 133.6793933995068,
"server_probe_mean": 74.19702970655635,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "c_1080p_0face",
"run": 1,
"p50": 111.00122199422913,
"p90": 117.57378029578831,
"server_probe_mean": 69.54348748549819,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "health_floor",
"run": 1,
"p50": 30.578960999264382,
"p90": 35.473932592140045,
"server_probe_mean": null,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "a_1080p_1face",
"run": 1,
"p50": 954.5748219970847,
"p90": 1020.2096714929212,
"server_probe_mean": 887.6064898984623,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "b_960x1001_2face",
"run": 1,
"p50": 1327.6250180060742,
"p90": 1416.4716226019664,
"server_probe_mean": 1270.2313813992077,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "c_1080p_0face",
"run": 1,
"p50": 202.1412319954834,
"p90": 210.3825692931423,
"server_probe_mean": 159.44489179673837,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "health_floor",
"run": 1,
"p50": 27.60758400108898,
"p90": 29.759886700776406,
"server_probe_mean": null,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "a_1080p_1face",
"run": 1,
"p50": 203.55955500417622,
"p90": 219.8045792974881,
"server_probe_mean": 156.9333346793428,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "b_960x1001_2face",
"run": 1,
"p50": 236.35765750077553,
"p90": 282.70697479892993,
"server_probe_mean": 188.06166611611843,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "c_1080p_0face",
"run": 1,
"p50": 110.56056749657728,
"p90": 114.69427619013004,
"server_probe_mean": 72.52865270711482,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "health_floor",
"run": 1,
"p50": 31.095413498405833,
"p90": 35.30468289682176,
"server_probe_mean": null,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "a_1080p_1face",
"run": 1,
"p50": 204.55308200325817,
"p90": 235.17365920706652,
"server_probe_mean": 159.80161383049563,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "b_960x1001_2face",
"run": 1,
"p50": 223.66256099485327,
"p90": 244.09297520178376,
"server_probe_mean": 171.44956310512498,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "c_1080p_0face",
"run": 1,
"p50": 101.08870249678148,
"p90": 114.38059099891689,
"server_probe_mean": 61.86515123117715,
"bad": 0
},
{
"target": "esh-ml1 GPU",
"frame": "health_floor",
"run": 2,
"p50": 27.849696998600848,
"p90": 30.98080779891462,
"server_probe_mean": null,
"bad": 0
},
{
"target": "esh-ml1 GPU",
"frame": "a_1080p_1face",
"run": 2,
"p50": 196.5537174983183,
"p90": 208.61720069660805,
"server_probe_mean": 144.78365819668397,
"bad": 0
},
{
"target": "esh-ml1 GPU",
"frame": "b_960x1001_2face",
"run": 2,
"p50": 196.06467850098852,
"p90": 210.13995000248542,
"server_probe_mean": 138.73773735249415,
"bad": 0
},
{
"target": "esh-ml1 GPU",
"frame": "c_1080p_0face",
"run": 2,
"p50": 180.95635149802547,
"p90": 188.9815433023614,
"server_probe_mean": 136.1989213983179,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "health_floor",
"run": 2,
"p50": 27.323893991706427,
"p90": 31.146193096356004,
"server_probe_mean": null,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "a_1080p_1face",
"run": 2,
"p50": 126.6464070067741,
"p90": 133.9685394996195,
"server_probe_mean": 74.96715487213805,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "b_960x1001_2face",
"run": 2,
"p50": 122.7374875015812,
"p90": 126.5989876977983,
"server_probe_mean": 73.87235894566402,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "c_1080p_0face",
"run": 2,
"p50": 108.72362100053579,
"p90": 114.4327986999997,
"server_probe_mean": 69.35211137169972,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "health_floor",
"run": 2,
"p50": 26.6998285005684,
"p90": 31.021830906684055,
"server_probe_mean": null,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "a_1080p_1face",
"run": 2,
"p50": 792.7710255025886,
"p90": 1075.1574820023964,
"server_probe_mean": 795.2748078998411,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "b_960x1001_2face",
"run": 2,
"p50": 1325.6497279944597,
"p90": 1390.5041895020986,
"server_probe_mean": 1253.4432460510288,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "c_1080p_0face",
"run": 2,
"p50": 205.08419950056123,
"p90": 223.07179619820093,
"server_probe_mean": 168.24462699732976,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "health_floor",
"run": 2,
"p50": 27.37445900129387,
"p90": 32.55561870028032,
"server_probe_mean": null,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "a_1080p_1face",
"run": 2,
"p50": 204.45054300216725,
"p90": 220.60656060639303,
"server_probe_mean": 152.42901378078386,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "b_960x1001_2face",
"run": 2,
"p50": 216.0444700057269,
"p90": 276.679380304995,
"server_probe_mean": 179.3103247997351,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "c_1080p_0face",
"run": 2,
"p50": 111.58617900218815,
"p90": 116.30833300296217,
"server_probe_mean": 72.20571864163503,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "health_floor",
"run": 2,
"p50": 27.235380999627523,
"p90": 29.255447497416764,
"server_probe_mean": null,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "a_1080p_1face",
"run": 2,
"p50": 208.08351850428153,
"p90": 221.3218400007463,
"server_probe_mean": 150.44436159078032,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "b_960x1001_2face",
"run": 2,
"p50": 219.75871399627067,
"p90": 259.07196740736254,
"server_probe_mean": 166.02391808992252,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "c_1080p_0face",
"run": 2,
"p50": 100.5097349989228,
"p90": 107.63760179688688,
"server_probe_mean": 59.30270317476243,
"bad": 0
},
{
"target": "esh-ml1 GPU",
"frame": "health_floor",
"run": 3,
"p50": 26.72893099952489,
"p90": 31.63200489798328,
"server_probe_mean": null,
"bad": 0
},
{
"target": "esh-ml1 GPU",
"frame": "a_1080p_1face",
"run": 3,
"p50": 196.49402699724305,
"p90": 204.47104229824618,
"server_probe_mean": 142.17575855000177,
"bad": 0
},
{
"target": "esh-ml1 GPU",
"frame": "b_960x1001_2face",
"run": 3,
"p50": 194.01365749945398,
"p90": 203.67266629764345,
"server_probe_mean": 138.33359165437287,
"bad": 0
},
{
"target": "esh-ml1 GPU",
"frame": "c_1080p_0face",
"run": 3,
"p50": 177.55984649556922,
"p90": 184.63658349210164,
"server_probe_mean": 135.46126945293508,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "health_floor",
"run": 3,
"p50": 34.47381099977065,
"p90": 37.53316599468235,
"server_probe_mean": null,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "a_1080p_1face",
"run": 3,
"p50": 121.84531000093557,
"p90": 126.15792770229746,
"server_probe_mean": 75.25073911529034,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "b_960x1001_2face",
"run": 3,
"p50": 122.41429199639242,
"p90": 125.64870739151957,
"server_probe_mean": 73.74720136867836,
"bad": 0
},
{
"target": "fv-ml1 GPU1",
"frame": "c_1080p_0face",
"run": 3,
"p50": 109.15258450404508,
"p90": 114.19055700243916,
"server_probe_mean": 69.49142985977232,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "health_floor",
"run": 3,
"p50": 27.56448650325183,
"p90": 34.92588359804358,
"server_probe_mean": null,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "a_1080p_1face",
"run": 3,
"p50": 1023.3039910017396,
"p90": 1191.5021550987149,
"server_probe_mean": 939.7293467947748,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "b_960x1001_2face",
"run": 3,
"p50": 1306.9450249968213,
"p90": 1427.1712208035751,
"server_probe_mean": 1251.0824149969267,
"bad": 0
},
{
"target": "esh-ml1 CPU6",
"frame": "c_1080p_0face",
"run": 3,
"p50": 228.02160500577884,
"p90": 261.2633642929723,
"server_probe_mean": 153.0728507990716,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "health_floor",
"run": 3,
"p50": 53.94737450114917,
"p90": 107.14866449852707,
"server_probe_mean": null,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "a_1080p_1face",
"run": 3,
"p50": 203.5052149949479,
"p90": 222.22570729936706,
"server_probe_mean": 147.21799310063943,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "b_960x1001_2face",
"run": 3,
"p50": 222.4783574929461,
"p90": 276.977431504929,
"server_probe_mean": 179.41700990777463,
"bad": 0
},
{
"target": "fv-ml1 CPU6",
"frame": "c_1080p_0face",
"run": 3,
"p50": 112.70040849922225,
"p90": 125.06614489684581,
"server_probe_mean": 72.31316382531077,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "health_floor",
"run": 3,
"p50": 30.923282000003383,
"p90": 36.041059493436485,
"server_probe_mean": null,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "a_1080p_1face",
"run": 3,
"p50": 221.6059979982674,
"p90": 246.61138239607683,
"server_probe_mean": 155.86536910850555,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "b_960x1001_2face",
"run": 3,
"p50": 237.05747949861689,
"p90": 271.11399889254244,
"server_probe_mean": 167.3004158306867,
"bad": 0
},
{
"target": "fv-ml1 CPU24",
"frame": "c_1080p_0face",
"run": 3,
"p50": 113.37069750152295,
"p90": 157.2230929945363,
"server_probe_mean": 71.09609730541706,
"bad": 0
}
]
+23
View File
@@ -0,0 +1,23 @@
"""Summarise bench.py rows: per (target, frame), the median of the 3 run p50s with the
min-max of those run p50s (the A-vs-A spread, i.e. the noise floor), the median run p90,
and the median server-side probe mean.
python summarize.py rows-2026-09-27.json
"""
import json, statistics, sys
from collections import defaultdict
rows = json.load(open(sys.argv[1]))
g = defaultdict(list)
for r in rows:
g[(r["target"], r["frame"])].append(r)
targets = list(dict.fromkeys(r["target"] for r in rows))
frames = list(dict.fromkeys(r["frame"] for r in rows))
print(f"{'target':<14} {'frame':<17} {'p50 med':>8} {'p50 run min-max':>16} {'p90 med':>8} {'server med':>10} bad")
for t in targets:
for f in frames:
rs = g[(t, f)]
p50s = [r["p50"] for r in rs]
srv = [r["server_probe_mean"] for r in rs if r["server_probe_mean"] is not None]
print(f"{t:<14} {f:<17} {statistics.median(p50s):8.1f} {min(p50s):7.1f}-{max(p50s):<8.1f}"
f" {statistics.median(r['p90'] for r in rs):8.1f}"
f" {(statistics.median(srv) if srv else float('nan')):10.1f} {sum(r['bad'] for r in rs)}")