Files
club-3090/scripts/rebench-report.py
noonghunna 1055c9162f fix(rebench-report): surface ceiling VRAM margin in verify-stress section (#184)
verify-stress.sh already hard-fails a ceiling free-VRAM margin below the
sustained-agent guard (default 1024 MB), but a margin that *passes* the guard
yet sits close to it can still OOM on a second run or server restart — the
marginal-but-passing case @laurimyllari hit on his 4090 at 160K (8/8 PASS, then
a second rebench OOMed). The report dropped the margin number entirely, so a
PASS read as comfortable headroom.

parse_verify_stress now extracts the deepest-rung free VRAM + guard from the
existing verify-stress output (both the thin-margin and ok lines), classifies
it (thin < guard / marginal < 2× guard / comfortable), and the verify-stress
report section prints e.g. "Ceiling VRAM margin: 1500 MB free (guard 1024 MB)
— ⚠ marginal: ... a second run or server restart may OOM. Lower CTX_SIZE ...".

rebench-report.py only — no change to verify-stress.sh's pass/fail logic.
Validated parse on comfortable / marginal / thin / no-margin logs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 20:05:52 +00:00

979 lines
40 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""rebench-report.py — synthesize REPORT.md from a results/rebench/<tag>/ dir.
Reads the raw logs and JSON artifacts that scripts/rebench-full.sh writes,
extracts the structured numbers, and produces a single REPORT.md at the top
of the tag dir. Re-runnable standalone — just pass the tag-dir path.
Usage:
python3 scripts/rebench-report.py results/rebench/<tag>/
"""
from __future__ import annotations
import argparse
import json
import re
import subprocess
import sys
from collections import defaultdict
from pathlib import Path
from typing import Any
# --- file readers -----------------------------------------------------------
def read_file(path: Path) -> str:
if not path.is_file():
return ""
try:
return path.read_text(errors="replace")
except Exception:
return ""
def read_json(path: Path) -> Any:
if not path.is_file():
return None
try:
return json.loads(path.read_text(errors="replace"))
except Exception:
return None
# --- section: meta + config -------------------------------------------------
def parse_container_config(blob: dict | None) -> dict:
"""Pull the relevant bits from `docker inspect <container>`."""
if not blob:
return {}
# docker inspect returns a list with one element
if isinstance(blob, list) and blob:
blob = blob[0]
cfg = blob.get("Config", {}) or {}
state = blob.get("State", {}) or {}
mounts = blob.get("Mounts", [])
cmd = cfg.get("Cmd") or []
env = cfg.get("Env") or []
# extract flag values from Cmd list
def get_flag(name: str) -> str | None:
try:
i = cmd.index(name)
return cmd[i + 1]
except (ValueError, IndexError):
return None
# mounts that look like vendored patches
patches = []
for m in mounts:
src = m.get("Source", "")
if "/patches/" in src and m.get("Type") == "bind":
# take the patch dir name
parts = src.split("/patches/")
if len(parts) > 1:
name = parts[1].split("/")[0]
if name not in patches:
patches.append(name)
return {
"image": cfg.get("Image"),
"name": blob.get("Name", "").lstrip("/"),
"status": state.get("Status"),
"model": get_flag("--model") or "?",
"served_model_name": get_flag("--served-model-name") or "?",
"quantization": get_flag("--quantization") or "?",
"dtype": get_flag("--dtype") or "?",
"tensor_parallel_size": get_flag("--tensor-parallel-size") or "?",
"max_model_len": get_flag("--max-model-len") or "?",
"gpu_memory_utilization": get_flag("--gpu-memory-utilization") or "?",
"max_num_seqs": get_flag("--max-num-seqs") or "?",
"max_num_batched_tokens": get_flag("--max-num-batched-tokens") or "?",
"kv_cache_dtype": get_flag("--kv-cache-dtype") or "?",
"speculative_config": get_flag("--speculative-config") or "?",
"patches": patches,
"env": env,
}
def parse_model_config_json(model_dir: Path) -> dict:
"""Read config.json from the served model dir to get quant metadata."""
cfg_path = model_dir / "config.json"
if not cfg_path.is_file():
return {}
blob = read_json(cfg_path)
if not blob:
return {}
q = blob.get("quantization_config") or {}
return {
"model_type": blob.get("model_type"),
"architectures": blob.get("architectures") or [],
"quant_method": q.get("quant_method"),
"bits": q.get("bits"),
"group_size": q.get("group_size"),
}
# --- section: vLLM boot log (KV pool + max concurrency) ---------------------
def parse_vllm_boot(boot_log: str) -> dict:
"""Pull KV cache size and Max concurrency lines."""
out = {}
m = re.search(r"GPU KV cache size: ([\d,]+) tokens", boot_log)
if m:
out["kv_cache_tokens"] = int(m.group(1).replace(",", ""))
m = re.search(r"Maximum concurrency for ([\d,]+) tokens per request: ([\d.]+)x", boot_log)
if m:
out["max_concurrency_request_size"] = int(m.group(1).replace(",", ""))
out["max_concurrency"] = float(m.group(2))
m = re.search(r"Available KV cache memory: ([\d.]+) GiB", boot_log)
if m:
out["available_kv_cache_gib"] = float(m.group(1))
m = re.search(r"Model loading took ([\d.]+) GiB memory", boot_log)
if m:
out["model_load_gib"] = float(m.group(1))
return out
# --- section: bench.sh ------------------------------------------------------
def parse_bench(log: str) -> dict:
"""Extract narrative + code TPS summaries from bench.sh output."""
out: dict[str, Any] = {}
for kind in ("narrative", "code", "prompt-processing"):
block = re.search(
rf"=== summary \[{kind}\] \(n=\d+\) ===\s*\n"
rf"(?P<body>.*?)(?=\n==========|\n=== GPU state ===|\n=== Last|\Z)",
log,
re.DOTALL,
)
if not block:
continue
body = block.group("body")
parsed: dict[str, Any] = {}
m = re.search(r"\s+wall_TPS\s+mean=\s*([\d.]+)\s+std=\s*([\d.]+)\s+CV=\s*([\d.]+)%", body)
if m:
parsed["wall_tps_mean"] = float(m.group(1))
parsed["wall_tps_cv"] = float(m.group(3))
m = re.search(r"\s+decode_TPS\s+mean=\s*([\d.]+)\s+std=\s*([\d.]+)\s+CV=\s*([\d.]+)%", body)
if m:
parsed["decode_tps_mean"] = float(m.group(1))
parsed["decode_tps_cv"] = float(m.group(3))
m = re.search(r"\s+TTFT\s+mean=\s*([\d.]+)ms", body)
if m:
parsed["ttft_ms_mean"] = float(m.group(1))
m = re.search(r"\s+PP tok/s\s+mean=\s*([\d.]+)\s+std=\s*([\d.]+)\s+CV=\s*([\d.]+)%", body)
if m:
parsed["pp_tps_mean"] = float(m.group(1))
parsed["pp_tps_cv"] = float(m.group(3))
if parsed:
out[kind.replace("-", "_")] = parsed
# GPU state at end
gpu_block = re.search(r"=== GPU state ===\s*\n((?:\d.+\n){1,4})", log)
if gpu_block:
gpu_lines = gpu_block.group(1).strip().split("\n")
out["gpu_state"] = []
for line in gpu_lines:
parts = [p.strip() for p in line.split(",")]
if len(parts) >= 6:
out["gpu_state"].append({
"idx": parts[0],
"util_pct": parts[1],
"mem_used": parts[2],
"mem_total": parts[3],
"power_w": parts[4],
"temp_c": parts[5],
})
# MTP last metrics line
mtp_lines = re.findall(
r"Mean acceptance length: ([\d.]+), .* "
r"Per-position acceptance rate: ([^,]+), .* "
r"Avg Draft acceptance rate: ([\d.]+)%",
log,
)
if mtp_lines:
last = mtp_lines[-1]
out["mtp"] = {
"mean_accept_length": float(last[0]),
"per_position": last[1].strip(),
"avg_accept_rate": float(last[2]),
}
return out
# --- section: verify-stress -------------------------------------------------
def parse_verify_stress(log: str) -> dict:
"""Extract the 7-check verdict table."""
checks = []
# match lines like "[1/7] description ..." followed by ✓ or ✗
for m in re.finditer(r"\[(\d+/\d+)\] (.+?) \.\.\.\n(.*?)(?=\n\[\d+/\d+\]|\nAll stress|\Z)", log, re.DOTALL):
idx = m.group(1)
desc = m.group(2).strip()
body = m.group(3)
verdict = "PASS" if "" in body else ("FAIL" if "" in body else "?")
checks.append({"idx": idx, "desc": desc, "verdict": verdict})
overall = "PASS" if "All stress / boundary checks passed" in log else (
"FAIL" if any(c["verdict"] == "FAIL" for c in checks) else "?"
)
result = {"checks": checks, "overall": overall}
# Ceiling VRAM margin (#184). verify-stress.sh prints free VRAM at the
# deepest rung and hard-fails below the guard, but a margin that *passes*
# the guard yet sits close to it can still OOM on a second run / server
# restart (laurimyllari's marginal-but-passing case). Surface the number so
# a PASS isn't mistaken for comfortable headroom.
free = thresh = None
m_thin = re.search(r"VRAM margin thin at ceiling:\s*(\d+)\s*MB free\s*<\s*(\d+)\s*MB", log)
if m_thin:
free, thresh = int(m_thin.group(1)), int(m_thin.group(2))
else:
m_ok = re.search(r"VRAM:\s*\d+\s*\S+\s*(\d+)\s*MB[^\n]*margin threshold=(\d+)", log)
if m_ok:
free, thresh = int(m_ok.group(1)), int(m_ok.group(2))
if free is not None and thresh:
result["ceiling_vram_free_mb"] = free
result["vram_threshold_mb"] = thresh
result["vram_status"] = (
"thin" if free < thresh else "marginal" if free < 2 * thresh else "comfortable"
)
return result
# --- section: quality-full --------------------------------------------------
def parse_quality(blob: dict | None) -> dict:
if not blob:
return {}
packs = []
failure_examples: dict[str, list[str]] = defaultdict(list)
for p in blob.get("packs", []):
if p.get("pack_id") == "aider-polyglot-30":
continue # rendered separately
lat = p.get("latency") or {}
packs.append({
"pack_id": p.get("pack_id"),
"passed": p.get("passed"),
"total": p.get("total"),
"score_pct": round(100 * (p.get("score") or 0)),
"p50_latency_s": lat.get("p50") if isinstance(lat, dict) else None,
"p95_latency_s": lat.get("p95") if isinstance(lat, dict) else None,
"mean_latency_s": lat.get("mean") if isinstance(lat, dict) else None,
"status": p.get("status"),
})
# gather top-3 failures per pack for the report appendix
for s in (p.get("scenarios") or []):
if not s.get("passed", True):
pack = p.get("pack_id", "?")
sid = s.get("id") or (s.get("raw_scenario") or {}).get("id", "?")
fail = s.get("failure_mode") or "?"
detail = (s.get("detail") or "")[:140]
if len(failure_examples[pack]) < 3:
failure_examples[pack].append(f"{sid}: {fail}{detail}")
total_passed = sum(p["passed"] or 0 for p in packs)
total_total = sum(p["total"] or 0 for p in packs)
return {
"packs": packs,
"total_passed": total_passed,
"total_total": total_total,
"total_pct": round(100 * total_passed / max(total_total, 1)),
"failure_examples": dict(failure_examples),
}
# --- section: soak ----------------------------------------------------------
def parse_soak(log: str) -> dict:
out = {}
for key in ("verdict", "max_growth_mib", "errors", "silent_empty",
"p50_decode_tps", "p95_ttft_ms", "tps_retention", "boot_vram_mib"):
m = re.search(rf"\b{key}\b\s+(\S.+)$", log, re.MULTILINE)
if m:
out[key] = m.group(1).strip()
return out
# --- section: aider-polyglot ------------------------------------------------
def parse_aider(blob: dict | None) -> dict:
"""upstream_per_exercise can be either:
- dict keyed by '<lang>/<exercise>' (current shape from aider's benchmark.py)
- list of {language, passed} dicts (older or alt shape)
Handle both.
"""
if not blob:
return {}
for p in blob.get("packs", []):
if p.get("pack_id") != "aider-polyglot-30":
continue
s = (p.get("scenarios") or [{}])[0]
latency_s = s.get("latency_seconds")
trace = s.get("verifier_trace", {})
# Schema v3 nests the trace under .trace; older versions are flat.
inner = trace.get("trace", trace) or {}
per_ex = inner.get("upstream_per_exercise") or inner.get("per_exercise") or {}
per_lang: dict = defaultdict(lambda: [0, 0])
passed_total = 0
total = 0
if isinstance(per_ex, dict):
# current shape: keyed by "<lang>/<exercise>"
for path, entry in per_ex.items():
lang = path.split("/", 1)[0].lower() if "/" in path else "?"
per_lang[lang][1] += 1
total += 1
if entry.get("passed") is True or entry.get("tests_passed") is True \
or entry.get("status") == "pass":
per_lang[lang][0] += 1
passed_total += 1
elif isinstance(per_ex, list):
for entry in per_ex:
lang = (entry.get("language") or "?").lower()
per_lang[lang][1] += 1
total += 1
if entry.get("passed") is True or entry.get("status") == "pass":
per_lang[lang][0] += 1
passed_total += 1
# Prefer the top-level fields if they're set; fall back to our tally.
passed_count = s.get("passed_count") if s.get("passed_count") is not None else passed_total
total_count = s.get("total_count") if s.get("total_count") is not None else total
pass_rate = s.get("pass_rate")
if pass_rate is None and total_count:
pass_rate = passed_count / total_count
return {
"pass_rate": pass_rate,
"passed_count": passed_count,
"total_count": total_count,
"wall_seconds": latency_s,
"per_language": dict(per_lang),
"aider_commit": inner.get("aider_pinned_commit", ""),
"polyglot_commit": inner.get("polyglot_pinned_commit", ""),
"edit_format": inner.get("edit_format", ""),
}
return {}
# --- markdown rendering -----------------------------------------------------
def render(report: dict) -> str:
lines = []
lines.append(f"# Rebench report — {report.get('tag', '?')}")
lines.append("")
lines.append(f"_Generated by `scripts/rebench-report.py` from `{report.get('tag_dir')}`_")
lines.append("")
# --- headline TL;DR (auto-computed from data) ---
tldr = report.get("tldr", [])
if tldr:
lines.append("## TL;DR")
lines.append("")
for bullet in tldr:
lines.append(f"- {bullet}")
lines.append("")
# --- meta ---
meta = report.get("meta", {})
lines.append("## Meta")
lines.append("")
lines.append(f"- **Tag:** `{report.get('tag', '?')}`")
lines.append(f"- **Date:** {report.get('date', '?')}")
lines.append(f"- **Repo commit:** `{report.get('commit_sha', '?')}`")
if meta.get("model_config"):
mc = meta["model_config"]
lines.append(f"- **Model arch:** {mc.get('model_type', '?')} ({(mc.get('architectures') or ['?'])[0]})")
lines.append(f"- **Quant:** {mc.get('quant_method', '?')} {mc.get('bits', '?')}-bit, group_size {mc.get('group_size', '?')}")
if meta.get("container"):
c = meta["container"]
lines.append(f"- **Served as:** `{c.get('served_model_name')}` from `{c.get('model')}`")
lines.append(f"- **vLLM image:** `{c.get('image')}`")
lines.append(f"- **Container:** `{c.get('name')}`")
rig = meta.get("rig", {})
if rig:
if rig.get("hostname"):
lines.append(f"- **Rig hostname:** `{rig['hostname']}`")
if rig.get("gpus"):
lines.append(f"- **GPUs:** {', '.join(rig['gpus'])}")
if rig.get("power_cap_w"):
lines.append(f"- **Power cap:** {rig['power_cap_w']} W/card")
lines.append("")
# --- config ---
lines.append("## Config")
lines.append("")
if meta.get("container"):
c = meta["container"]
lines.append("| Setting | Value |")
lines.append("|---|---|")
lines.append(f"| `--tensor-parallel-size` | {c.get('tensor_parallel_size')} |")
lines.append(f"| `--max-model-len` | {c.get('max_model_len')} |")
lines.append(f"| `--gpu-memory-utilization` | {c.get('gpu_memory_utilization')} |")
lines.append(f"| `--max-num-seqs` | {c.get('max_num_seqs')} |")
lines.append(f"| `--max-num-batched-tokens` | {c.get('max_num_batched_tokens')} |")
lines.append(f"| `--kv-cache-dtype` | `{c.get('kv_cache_dtype')}` |")
lines.append(f"| `--dtype` | `{c.get('dtype')}` |")
lines.append(f"| `--quantization` | `{c.get('quantization')}` |")
lines.append(f"| `--speculative-config` | `{c.get('speculative_config')}` |")
patches = c.get("patches") or []
lines.append(f"| Patches mounted | {', '.join(f'`{p}`' for p in patches) if patches else 'none'} |")
# Genesis detection
genesis_envs = [e for e in (c.get("env") or []) if e.startswith("GENESIS_")]
lines.append(f"| Genesis | {'on (' + str(len(genesis_envs)) + ' GENESIS_* env vars)' if genesis_envs else 'none'} |")
lines.append("")
# --- bench performance ---
bench = report.get("bench", {})
lines.append("## Performance — `bench.sh`")
lines.append("")
if bench.get("narrative") or bench.get("code"):
lines.append("| Bench | wall TPS | decode TPS | PP tok/s | TTFT | CV (wall/decode) |")
lines.append("|---|---:|---:|---:|---:|---:|")
for kind in ("narrative", "code"):
b = bench.get(kind)
if b:
pp = f"{b['pp_tps_mean']:.0f}" if b.get("pp_tps_mean") is not None else "n/a"
lines.append(
f"| {kind} | {b['wall_tps_mean']:.2f} | **{b['decode_tps_mean']:.2f}** | {pp} | "
f"{b['ttft_ms_mean']:.0f} ms | {b['wall_tps_cv']:.1f}% / {b['decode_tps_cv']:.1f}% |"
)
pp_fallback = bench.get("prompt_processing")
if pp_fallback and pp_fallback.get("pp_tps_mean") is not None:
lines.append(
f"| prompt-processing fallback | — | — | **{pp_fallback['pp_tps_mean']:.0f}** | "
f"{pp_fallback.get('ttft_ms_mean', 0):.0f} ms | — |"
)
if bench.get("mtp"):
m = bench["mtp"]
lines.append("")
lines.append(f"**MTP (warm, last metric):** mean accept length {m['mean_accept_length']:.2f}, "
f"avg accept rate {m['avg_accept_rate']:.1f}%, per-position {m['per_position']}")
if bench.get("gpu_state"):
lines.append("")
lines.append("**GPU state at bench end:**")
lines.append("")
lines.append("| GPU | Util | Mem used / total | Power | Temp |")
lines.append("|---|---|---|---|---|")
for g in bench["gpu_state"]:
lines.append(f"| {g['idx']} | {g['util_pct']} | {g['mem_used']} / {g['mem_total']} | {g['power_w']} | {g['temp_c']} |")
else:
lines.append("_(bench artifacts missing)_")
lines.append("")
# --- concurrency + VRAM ---
boot = report.get("vllm_boot", {})
lines.append("## Concurrency + VRAM")
lines.append("")
if boot:
kv_tokens = boot.get("kv_cache_tokens")
max_conc = boot.get("max_concurrency")
req_size = boot.get("max_concurrency_request_size")
avail = boot.get("available_kv_cache_gib")
model_load = boot.get("model_load_gib")
lines.append("| Metric | Value |")
lines.append("|---|---:|")
if model_load:
lines.append(f"| Model load footprint | {model_load:.2f} GiB |")
if avail:
lines.append(f"| Available KV cache memory (per card, post-profiling) | {avail:.2f} GiB |")
if kv_tokens:
lines.append(f"| GPU KV cache size | **{kv_tokens:,} tokens** |")
if max_conc and req_size:
lines.append(f"| Max concurrency @ {req_size:,} tokens/req | **{max_conc:.2f}×** |")
if req_size > 1:
for ctx in (100_000, 32_000):
practical = max_conc * (req_size / ctx)
lines.append(f"| Practical concurrency @ {ctx:,} tokens/req | ~{practical:.1f}× |")
else:
lines.append("_(no vLLM boot log captured)_")
lines.append("")
# --- verify-stress ---
stress = report.get("verify_stress", {})
lines.append("## Verify-stress — 7-check boundary matrix")
lines.append("")
if stress.get("checks"):
lines.append(f"**Overall:** {stress.get('overall')}")
lines.append("")
lines.append("| # | Check | Verdict |")
lines.append("|---|---|---|")
for c in stress["checks"]:
lines.append(f"| {c['idx']} | {c['desc']} | {c['verdict']} |")
if stress.get("ceiling_vram_free_mb") is not None:
free = stress["ceiling_vram_free_mb"]
thresh = stress["vram_threshold_mb"]
note = {
"thin": " — ⚠ **THIN** (below the sustained-agent guard; verify-stress fails this check)",
"marginal": " — ⚠ **marginal**: within 2× the guard, so a second run or server restart may OOM. Lower `CTX_SIZE` for sustained agent load.",
"comfortable": " — ✓ comfortable",
}[stress["vram_status"]]
lines.append("")
lines.append(f"**Ceiling VRAM margin:** {free} MB free (guard {thresh} MB){note}")
else:
lines.append("_(verify-stress log missing or unparsed)_")
lines.append("")
# --- quality ---
quality = report.get("quality", {})
lines.append("## Quality — `quality-test.sh --full`")
lines.append("")
if quality.get("packs"):
lines.append("| Pack | Pass / Total | Score | p50 latency | p95 latency |")
lines.append("|---|---:|---:|---:|---:|")
for p in quality["packs"]:
p50 = f"{p['p50_latency_s']:.2f}s" if p.get("p50_latency_s") is not None else ""
p95 = f"{p['p95_latency_s']:.2f}s" if p.get("p95_latency_s") is not None else ""
lines.append(f"| {p['pack_id']} | {p['passed']} / {p['total']} | {p['score_pct']}% | {p50} | {p95} |")
lines.append(f"| **TOTAL** | **{quality['total_passed']} / {quality['total_total']}** | **{quality['total_pct']}%** | | |")
if quality.get("one_liner"):
lines.append("")
lines.append("**Paste-ready compose `Quality:` schema line:**")
lines.append("```")
lines.append(quality["one_liner"])
lines.append("```")
if quality.get("failure_examples"):
lines.append("")
lines.append("**Failure examples (top 3 per pack):**")
for pack, examples in sorted(quality["failure_examples"].items()):
lines.append(f"- `{pack}`:")
for ex in examples:
lines.append(f" - {ex}")
else:
lines.append("_(quality JSON missing or unparsed)_")
lines.append("")
# --- soak ---
soak = report.get("soak", {})
lines.append("## Soak — `soak-test.sh`")
lines.append("")
if soak:
lines.append("| Metric | Value |")
lines.append("|---|---|")
for k in ("verdict", "silent_empty", "p50_decode_tps", "p95_ttft_ms",
"tps_retention", "max_growth_mib", "errors", "boot_vram_mib"):
if k in soak:
lines.append(f"| `{k}` | {soak[k]} |")
else:
lines.append("_(soak log missing or unparsed)_")
lines.append("")
# --- aider-polyglot ---
aider = report.get("aider", {})
lines.append("## Aider Polyglot 30 — per-language breakdown")
lines.append("")
if aider.get("per_language"):
lines.append(f"**Total:** {aider.get('passed_count', '?')} / {aider.get('total_count', '?')} "
f"({100 * (aider.get('pass_rate') or 0):.1f}%) · "
f"wall {aider.get('wall_seconds', 0):.0f}s")
lines.append("")
lines.append("| Language | Pass / Total | Score |")
lines.append("|---|---:|---:|")
for lang, (passed, total) in sorted(aider["per_language"].items()):
pct = round(100 * passed / total) if total else 0
lines.append(f"| {lang} | {passed} / {total} | {pct}% |")
else:
lines.append("_(aider-polyglot artifacts missing or no per-exercise trace)_")
lines.append("")
# --- phase timings ---
timings = report.get("timings", {})
if timings:
lines.append("## Phase timings")
lines.append("")
lines.append("| Phase | Duration |")
lines.append("|---|---:|")
total_s = 0
for phase, secs in timings.items():
if isinstance(secs, (int, float)) and secs > 0:
m, s = divmod(int(secs), 60)
lines.append(f"| {phase} | {m}m {s}s |")
total_s += secs
if total_s:
tm, ts = divmod(int(total_s), 60)
lines.append(f"| **Total** | **{tm}m {ts}s** |")
lines.append("")
# --- reproducer ---
repro = report.get("reproducer", {})
if repro:
lines.append("## Reproduce on your rig")
lines.append("")
lines.append("```bash")
for line in repro.get("commands", []):
lines.append(line)
lines.append("```")
lines.append("")
# --- delta vs prior tag (when --compare-to given) ---
delta = report.get("delta", {})
if delta:
lines.append(f"## Delta vs `{delta.get('compare_to', '?')}`")
lines.append("")
for section, rows in delta.get("sections", {}).items():
if rows:
lines.append(f"### {section}")
lines.append("")
lines.append("| Metric | this | prior | Δ |")
lines.append("|---|---:|---:|---:|")
for r in rows:
lines.append(f"| {r['metric']} | {r['this']} | {r['prior']} | {r['delta']} |")
lines.append("")
return "\n".join(lines)
def render_discuss(report: dict) -> str:
"""Trimmed variant for posting under a GitHub Discussion comment.
Drops failure examples + bench raw GPU table; keeps the headline tables."""
lines = []
lines.append(f"**Rebench — {report.get('tag', '?')}**")
lines.append("")
if report.get("tldr"):
for b in report["tldr"]:
lines.append(f"- {b}")
lines.append("")
meta = report.get("meta", {})
c = meta.get("container", {})
if c:
# Quant string: prefer model_config bits, fall back to quantization scheme name.
mc = meta.get("model_config", {}) or {}
quant_str = f"{mc.get('quant_method', c.get('quantization', '?'))} {mc.get('bits', '?')}-bit" \
if mc.get("bits") else c.get("quantization", "?")
lines.append(f"Config: `{c.get('image')}` · {quant_str} · "
f"`{c.get('kv_cache_dtype')}` KV · `{c.get('max_model_len')}` ctx · "
f"`{c.get('speculative_config')}` · TP={c.get('tensor_parallel_size')}")
lines.append("")
# bench
bench = report.get("bench", {})
if bench.get("narrative"):
b_n, b_c = bench["narrative"], bench.get("code", {})
lines.append("**TPS:**")
pp_n = f", PP {b_n['pp_tps_mean']:.0f} tok/s" if b_n.get("pp_tps_mean") is not None else ""
lines.append(f"- Narrative: {b_n['decode_tps_mean']:.1f} TPS decode, {b_n['ttft_ms_mean']:.0f} ms TTFT{pp_n} (CV {b_n['decode_tps_cv']:.1f}%)")
if b_c:
pp_c = f", PP {b_c['pp_tps_mean']:.0f} tok/s" if b_c.get("pp_tps_mean") is not None else ""
lines.append(f"- Code: {b_c['decode_tps_mean']:.1f} TPS decode, {b_c['ttft_ms_mean']:.0f} ms TTFT{pp_c} (CV {b_c['decode_tps_cv']:.1f}%)")
if bench.get("prompt_processing", {}).get("pp_tps_mean") is not None:
pp = bench["prompt_processing"]["pp_tps_mean"]
lines.append(f"- Prompt-processing fallback: {pp:.0f} tok/s")
lines.append("")
boot = report.get("vllm_boot", {})
if boot.get("kv_cache_tokens"):
lines.append(f"**Concurrency:** GPU KV pool **{boot['kv_cache_tokens']:,} tokens**, "
f"**{boot.get('max_concurrency', 0):.2f}×** concurrency @ {boot.get('max_concurrency_request_size', 0):,} tokens/req.")
lines.append("")
stress = report.get("verify_stress", {})
if stress.get("checks"):
passed = sum(1 for c in stress["checks"] if c["verdict"] == "PASS")
total = len(stress["checks"])
lines.append(f"**Stress:** {passed}/{total} checks PASS.")
lines.append("")
q = report.get("quality", {})
if q.get("packs"):
rows = " · ".join(f"{p['pack_id']} {p['passed']}/{p['total']} ({p['score_pct']}%)" for p in q["packs"])
lines.append(f"**Quality:** {q['total_passed']}/{q['total_total']} ({q['total_pct']}%) — {rows}")
lines.append("")
soak = report.get("soak", {})
if soak:
lines.append(f"**Soak:** verdict {soak.get('verdict', '?')}, "
f"silent_empty {soak.get('silent_empty', '?')}, "
f"p50 decode {soak.get('p50_decode_tps', '?')} TPS.")
lines.append("")
aider = report.get("aider", {})
if aider.get("per_language"):
per_lang_str = " · ".join(f"{l} {p}/{t}" for l, (p, t) in sorted(aider["per_language"].items()))
lines.append(f"**Aider-polyglot:** {aider.get('passed_count', '?')}/{aider.get('total_count', '?')}{per_lang_str}")
lines.append("")
return "\n".join(lines)
# --- helpers for the new sections -------------------------------------------
def compute_tldr(report: dict) -> list[str]:
"""Auto-generate 3-5 punchy bullets from the parsed data."""
bullets = []
bench = report.get("bench", {})
if bench.get("narrative") and bench.get("code"):
pp_vals = [
b.get("pp_tps_mean")
for b in (bench.get("narrative", {}), bench.get("code", {}))
if b.get("pp_tps_mean") is not None
]
pp_text = f", PP {sum(pp_vals) / len(pp_vals):.0f} tok/s" if pp_vals else ""
bullets.append(
f"TPS narrative **{bench['narrative']['decode_tps_mean']:.1f}** / "
f"code **{bench['code']['decode_tps_mean']:.1f}** "
f"(TTFT {bench['narrative']['ttft_ms_mean']:.0f}/{bench['code']['ttft_ms_mean']:.0f} ms{pp_text})."
)
elif bench.get("prompt_processing"):
pp = bench["prompt_processing"].get("pp_tps_mean")
if pp is not None:
bullets.append(f"Prompt processing fallback: **{pp:.0f} tok/s**.")
boot = report.get("vllm_boot", {})
if boot.get("kv_cache_tokens") and boot.get("max_concurrency"):
bullets.append(
f"KV pool **{boot['kv_cache_tokens']:,} tokens** — "
f"**{boot['max_concurrency']:.2f}×** concurrency @ {boot.get('max_concurrency_request_size', 0):,} tokens/req."
)
stress = report.get("verify_stress", {})
if stress.get("checks"):
passed = sum(1 for c in stress["checks"] if c["verdict"] == "PASS")
total = len(stress["checks"])
bullets.append(f"Verify-stress: **{passed}/{total}** boundary checks PASS.")
q = report.get("quality", {})
if q.get("total_total"):
bullets.append(
f"Quality (8 packs, {q['total_total']} scenarios): **{q['total_passed']}/{q['total_total']} ({q['total_pct']}%)**."
)
soak = report.get("soak", {})
if soak.get("verdict"):
bullets.append(
f"Soak: **{soak['verdict']}** — silent_empty {soak.get('silent_empty', '?')}, "
f"p50 decode {soak.get('p50_decode_tps', '?')} TPS."
)
a = report.get("aider", {})
if a.get("total_count"):
bullets.append(
f"Aider-polyglot: **{a.get('passed_count', '?')}/{a['total_count']}** "
f"({100 * (a.get('pass_rate') or 0):.1f}%) — per-lang in section below."
)
return bullets
def parse_rig(rig_txt: str) -> dict:
"""Parse rig.txt captured by rebench-full.sh.
Format: free-form key: value lines from `nvidia-smi -L`, hostname, etc."""
rig = {"gpus": []}
for line in rig_txt.splitlines():
line = line.strip()
if not line:
continue
if line.startswith("hostname:"):
rig["hostname"] = line.split(":", 1)[1].strip()
elif line.startswith("GPU "):
# `nvidia-smi -L` format: "GPU 0: NVIDIA GeForce RTX 3090 (UUID: GPU-xxx)"
rig["gpus"].append(line.split(":", 1)[1].split("(UUID")[0].strip())
elif line.startswith("power_cap_w:"):
rig["power_cap_w"] = line.split(":", 1)[1].strip()
return rig
def compute_reproducer(meta: dict) -> dict:
"""Render bash commands to re-run this exact config."""
c = meta.get("container", {})
cmds = []
if c.get("image"):
cmds.append("# Same vLLM nightly + KV class + ctx + MTP n as this run:")
cmds.append(f"# image: {c['image']}")
cmds.append("")
cmds.append("# Bring the model up via gpu-mode (or docker compose -f <compose>.yml up -d):")
cmds.append(f"# served_model_name = {c.get('served_model_name', '?')}")
cmds.append("")
cmds.append("bash scripts/rebench-full.sh")
cmds.append("")
cmds.append("# Or run individual phases:")
cmds.append("bash scripts/bench.sh # TPS")
cmds.append("bash scripts/verify-stress.sh # boundary")
cmds.append("bash scripts/quality-test.sh --full # 8-pack quality")
cmds.append("bash scripts/soak-test.sh # stability")
cmds.append("bash scripts/quality-test.sh --pack aider-polyglot-30")
return {"commands": cmds}
def compute_delta(this_report: dict, other_dir: Path) -> dict:
"""Diff this report against another tag dir's REPORT.md numerical fields."""
other_blob = read_json(other_dir / "_internal.json")
if not other_blob:
return {}
sections = {}
def num(v):
try:
return float(v)
except (TypeError, ValueError):
return None
def diff_row(label, a, b, unit=""):
an, bn = num(a), num(b)
if an is None or bn is None:
return None
d = an - bn
sign = "+" if d > 0 else ""
return {"metric": label, "this": f"{an:.2f}{unit}", "prior": f"{bn:.2f}{unit}",
"delta": f"{sign}{d:.2f}{unit}"}
perf_rows = []
for kind in ("narrative", "code"):
t = (this_report.get("bench", {}) or {}).get(kind, {})
o = (other_blob.get("bench", {}) or {}).get(kind, {})
if t and o:
r = diff_row(f"{kind} decode TPS", t.get("decode_tps_mean"), o.get("decode_tps_mean"))
if r: perf_rows.append(r)
r = diff_row(f"{kind} TTFT", t.get("ttft_ms_mean"), o.get("ttft_ms_mean"), " ms")
if r: perf_rows.append(r)
sections["Performance"] = perf_rows
conc_rows = []
t = this_report.get("vllm_boot", {})
o = other_blob.get("vllm_boot", {})
r = diff_row("GPU KV cache tokens", t.get("kv_cache_tokens"), o.get("kv_cache_tokens"))
if r: conc_rows.append(r)
r = diff_row("Max concurrency", t.get("max_concurrency"), o.get("max_concurrency"), "×")
if r: conc_rows.append(r)
sections["Concurrency"] = conc_rows
qual_rows = []
t = this_report.get("quality", {})
o = other_blob.get("quality", {})
r = diff_row("Total passes", t.get("total_passed"), o.get("total_passed"))
if r: qual_rows.append(r)
r = diff_row("Total %", t.get("total_pct"), o.get("total_pct"), "%")
if r: qual_rows.append(r)
sections["Quality"] = qual_rows
aid_rows = []
t = this_report.get("aider", {})
o = other_blob.get("aider", {})
r = diff_row("aider-polyglot passes", t.get("passed_count"), o.get("passed_count"))
if r: aid_rows.append(r)
sections["Aider Polyglot"] = aid_rows
return {"compare_to": other_dir.name, "sections": sections}
# --- main -------------------------------------------------------------------
def extract_date(tag_dir: Path) -> str:
"""Tag-dir date: look for YYYY-MM-DD or YYYYMMDD anywhere in the name,
otherwise fall back to the dir mtime."""
m = re.search(r"(\d{4}-\d{2}-\d{2}|\d{8})", tag_dir.name)
if m:
s = m.group(1)
if len(s) == 8:
return f"{s[:4]}-{s[4:6]}-{s[6:8]}"
return s
import datetime
return datetime.datetime.utcfromtimestamp(tag_dir.stat().st_mtime).strftime("%Y-%m-%d")
def extract_quality_oneliner(qfull_log: str) -> str | None:
"""Grep the paste-ready Quality: line from quality-test.sh stdout."""
for line in qfull_log.splitlines():
if line.lstrip().startswith("Quality:"):
return line.strip()
return None
def main(argv=None):
p = argparse.ArgumentParser()
p.add_argument("tag_dir", help="results/rebench/<tag>/ directory")
p.add_argument("--compare-to", default=None,
help="another tag dir to compute deltas against")
p.add_argument("--no-discuss", action="store_true",
help="skip writing REPORT-discuss.md")
args = p.parse_args(argv)
tag_dir = Path(args.tag_dir).resolve()
if not tag_dir.is_dir():
print(f"✗ not a directory: {tag_dir}", file=sys.stderr)
return 2
bench_log = read_file(tag_dir / "bench.log")
stress_log = read_file(tag_dir / "verify-stress.log")
quality_blob = read_json(tag_dir / "quality-full.json")
quality_log = read_file(tag_dir / "quality-full.log")
soak_log = read_file(tag_dir / "soak.log")
aider_blob = read_json(tag_dir / "aider-polyglot.json")
container_blob = read_json(tag_dir / "container-config.json")
boot_log = read_file(tag_dir / "vllm-boot.log")
timings_blob = read_json(tag_dir / "timings.json") or {}
rig_txt = read_file(tag_dir / "rig.txt")
# find model dir for quant config
model_config = {}
if container_blob:
cinfo = parse_container_config(container_blob)
model_path = cinfo.get("model", "")
if model_path and model_path.startswith("/root/.cache/huggingface/"):
host_path = Path("/mnt/models/huggingface") / Path(model_path).name
model_config = parse_model_config_json(host_path)
# commit SHA from the club-3090 repo (walk up to find .git)
sha_dir = tag_dir
while sha_dir != sha_dir.parent and not (sha_dir / ".git").exists():
sha_dir = sha_dir.parent
commit_sha = subprocess.run(
["git", "rev-parse", "--short", "HEAD"],
cwd=str(sha_dir if (sha_dir / ".git").exists() else tag_dir),
capture_output=True, text=True,
).stdout.strip() or "?"
quality = parse_quality(quality_blob)
one_liner = extract_quality_oneliner(quality_log)
if one_liner:
quality["one_liner"] = one_liner
report = {
"tag": tag_dir.name,
"tag_dir": str(tag_dir),
"date": extract_date(tag_dir),
"commit_sha": commit_sha,
"meta": {
"container": parse_container_config(container_blob),
"model_config": model_config,
"rig": parse_rig(rig_txt),
},
"vllm_boot": parse_vllm_boot(boot_log),
"bench": parse_bench(bench_log),
"verify_stress": parse_verify_stress(stress_log),
"quality": quality,
"soak": parse_soak(soak_log),
"aider": parse_aider(aider_blob),
"timings": timings_blob,
}
# auto-compute TL;DR
report["tldr"] = compute_tldr(report)
report["reproducer"] = compute_reproducer(report.get("meta", {}))
# optional delta vs prior tag
if args.compare_to:
other = Path(args.compare_to).resolve()
if other.is_dir():
report["delta"] = compute_delta(report, other)
# write a sidecar with the parsed numbers so future --compare-to works
sidecar = {
"bench": report["bench"],
"vllm_boot": report["vllm_boot"],
"quality": {
"total_passed": report["quality"].get("total_passed"),
"total_total": report["quality"].get("total_total"),
"total_pct": report["quality"].get("total_pct"),
"packs": report["quality"].get("packs"),
},
"aider": {
"passed_count": report["aider"].get("passed_count"),
"total_count": report["aider"].get("total_count"),
"per_language": report["aider"].get("per_language"),
},
"soak": report["soak"],
}
(tag_dir / "_internal.json").write_text(json.dumps(sidecar, indent=2))
out_path = tag_dir / "REPORT.md"
out_path.write_text(render(report))
print(f"wrote {out_path}")
if not args.no_discuss:
discuss_path = tag_dir / "REPORT-discuss.md"
discuss_path.write_text(render_discuss(report))
print(f"wrote {discuss_path}")
return 0
if __name__ == "__main__":
sys.exit(main())