Files
felhom.eu/documentation/audits/immich-first-start-2026-09-30/tools/benchq.py
T
admin 2866f6a318
gates / gates (push) Successful in 27s
immich's first start: cause measured, fixed in the catalog (R-732 closed); ISO clean-tree gate (R-730 closed)
- R-732: the first-start geodata import runs up to 9 concurrent 5000-row INSERTs; the database needs
  ~400 MB anon + ~170 MB touched shared_buffers (the image's FIXED 512MB, not host-RAM sizing). 512M fits
  only with swap (bench swap 0: 61-104 kills; 9202 swap 512 MiB: survived by swapping). Controls: swap
  alone, limit alone flip it; shared_buffers 128MB alone does not. Catalog 56c4888: v3.2.4 + 768M,
  proven with swap off on both venues. audits/immich-first-start-2026-09-30/A-cause.md.
- R-730: scripts/iso/build-felhom-iso.sh refuses an uncommitted/untracked/unpushed tree (no bypass),
  records repo-commit from the gate and iso-v<version>; test iso/test/clean-tree.sh, red-proof run
  (status check removed -> 2 of 4 cases fail -> restored).
- R-731 narrowed (gitea 28.0.0 GA; mariadb 13.0 a short-term Rolling line). R-676 note.
- New rows R-733 (bench has no swap, boxes 512 MiB), R-734 (immich .immich markers -> files_may_change).
- STATUS: the golden line corrected (no bake is due; 0.283.1 is the newest release). Register 364 -> 366.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 16:18:17 +02:00

49 lines
2.8 KiB
Python

#!/usr/bin/env python3
"""benchq.py <queue-name> <app> <svc=ref>[,<svc=ref>] [<app> <moves> ...]
Runs `upgrade-test.py --move` on bench LXC 9401 for each app IN ORDER, then copies that edge's
evidence OFF the bench into apps/<app>/bench/ before starting the next (R-320: the evidence leaves
the machine at the end of the phase that made it). One line per finished edge in benchq-<queue>.txt.
"""
import json, os, subprocess, sys, time
HERE = os.path.dirname(os.path.abspath(__file__))
BENCH = "/tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/cf537324-9792-42e8-88e0-1a0b2ea3d378/scratchpad/bench.sh"
q = sys.argv[1]
args = sys.argv[2:]
out = open(os.path.join(HERE, "..", os.environ.get("BQ", "bench"), f"benchq-{q}.txt"), "a", buffering=1)
for i in range(0, len(args), 2):
app, moves = args[i], args[i + 1].split(",")
label = app
if "@" in app: # romm@engine: a second edge of one app gets its own folder
app, tag = app.split("@", 1)
label = f"{app}-{tag}"
t0 = time.time()
out.write(f"{time.strftime('%H:%M:%S')} START {app} {moves}\n")
pre = f"cd /opt/upg && [ -d evidence/MV-{app} ] && mv evidence/MV-{app} evidence/MV-{app}-$(date +%s); "
subprocess.run([BENCH], input=pre, capture_output=True, text=True, timeout=120)
cmd = (f"cd /opt/upg && timeout 2400 python3 upgrade-test.py --soak 600 --move {app} {' '.join(moves)} "
f"> /opt/upg/MV-{app}.log 2>&1; echo rc=$?")
r = subprocess.run([BENCH], input=cmd, capture_output=True, text=True, timeout=2700)
dest = os.path.join(HERE, "..", os.environ.get("BQ", "bench"), "apps", label, "bench")
os.makedirs(dest, exist_ok=True)
pull = (f"cd /opt/upg && tar czf /tmp/ev-{app}.tgz MV-{app}.log evidence/MV-{app} 2>/dev/null; "
f"base64 -w0 /tmp/ev-{app}.tgz")
r2 = subprocess.run([BENCH], input=pull, capture_output=True, text=True, timeout=600)
import base64, io, tarfile
try:
tarfile.open(fileobj=io.BytesIO(base64.b64decode(r2.stdout.strip()))).extractall(dest)
except Exception as e:
out.write(f" evidence pull FAILED for {app}: {e}\n")
v = {}
try:
v = json.load(open(os.path.join(dest, "evidence", f"MV-{app}", "verdict.json")))
except Exception:
pass
mem = v.get("memory") or {}
peaks = {n: c.get("peak_pct") for n, c in (mem.get("containers") or {}).items()}
out.write(f"{time.strftime('%H:%M:%S')} DONE {app} {r.stdout.strip()} verdict={v.get('verdict')} "
f"read_before={v.get('seed_read_before')} read_after={v.get('seed_read_after')} "
f"abort={v.get('abort')} marks={v.get('marks')} peaks={peaks} "
f"detail={str(v.get('abort_detail'))[:160]!r} ({round(time.time()-t0)}s)\n")
out.write(f"{time.strftime('%H:%M:%S')} QUEUE {q} FINISHED\n")