gqa(decode-4cases): wire latency + engine occupancy into sweep.json; add comparative plot script (5C.F)

Bench changes:
  - new _end_to_end_ns(op_log) and _engine_occupancy_ns(op_log) helpers
    in milestone_gqa_decode_long_ctx_4cases.py (mirror paper_gqa_latency.py)
  - _run_panel return dict now carries latency_ns + engine_occupancy_ns
    alongside op_log_summary, so sweep.json is the single source of truth
    for the comparative figures

Plot script:
  - new scripts/paper/paper_plot_gqa_decode_long_ctx_4cases.py reads
    sweep.json and emits 3 PNGs to docs/report/1H-codesign-paper/figures/:
      gqa_decode_long_ctx_4cases_latency.png   (end-to-end latency / case)
      gqa_decode_long_ctx_4cases_traffic.png   (ipcq/dma op counts / case)
      gqa_decode_long_ctx_4cases_memory.png    (KV bytes per cube / case)

Test changes:
  - 2 new tests verifying the helpers + _run_panel dict shape
  - lower smoke S_kv from 8192 -> 2048 (4x faster Case 2; assertions
    are S_kv-independent; one fold-loop iteration preserved)

18/18 tests pass in ~4 min.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 17:06:13 -07:00
parent 7f437a20bd
commit 1fbe833992
3 changed files with 274 additions and 14 deletions
@@ -258,6 +258,33 @@ def _make_bench_fn(panel: str):
return _bench_fn
# ── Panel metrics (sweep.json carries these for the comparative plot) ─
_ENGINE_SUFFIXES = (
"pe_gemm", "pe_math", "pe_dma", "pe_fetch_store", "pe_ipcq", "pe_cpu",
)
def _end_to_end_ns(op_log) -> float:
"""End-to-end window: ``max(t_end) - min(t_start)`` over all records."""
if not op_log:
return 0.0
return max(r.t_end for r in op_log) - min(r.t_start for r in op_log)
def _engine_occupancy_ns(op_log) -> dict[str, float]:
"""Per-engine summed occupancy (component_id suffix match)."""
return {
eng: sum(
r.t_end - r.t_start
for r in op_log
if r.component_id.endswith("." + eng)
)
for eng in _ENGINE_SUFFIXES
}
def _run_panel(panel: str, topology: str) -> dict:
from kernbench.runtime_api.bench_runner import run_bench
from kernbench.runtime_api.types import resolve_device
@@ -278,11 +305,14 @@ def _run_panel(panel: str, topology: str) -> dict:
f"{result.completion}"
)
kind, params = _PANEL_DISPATCH[panel]
op_log = result.engine.op_log
return {
"panel": panel,
"kind": kind,
**params,
"op_log_summary": _summarize_op_log(result.engine.op_log),
"op_log_summary": _summarize_op_log(op_log),
"latency_ns": _end_to_end_ns(op_log),
"engine_occupancy_ns": _engine_occupancy_ns(op_log),
}