"""Batch-scaling figure for concurrent decode users on one SIP.

Reads ``docs/sweeps/decode_batch_sweep.csv`` (from
``tests/attention/test_gqa_decode_batch_sweep.py``) and plots aggregate
throughput (requests / us) versus batch size B for the four KV mappings,
one panel per context length. Each mapping's curve runs up to its SIP
capacity 16/C (A1=2 ... B=16 users).
"""
from pathlib import Path

import csv

import matplotlib.pyplot as plt

ROOT = Path(__file__).resolve().parents[3]
CSV = ROOT / "docs" / "sweeps" / "decode_batch_sweep.csv"
OUT = (ROOT / "docs" / "report" / "1H-codesign-paper"
       / "figures" / "gqa_short_context" / "batch_scaling.png")

MODE_LABEL = {"A1": "1-kv-per-cube", "A2": "2-kv-per-cube",
              "A4": "4-kv-per-cube", "B": "8-kv-per-cube"}
MODE_COLOR = {"A1": "#1f77b4", "A2": "#2ca02c",
              "A4": "#ffd000", "B": "#d62728"}
MODES = ["A1", "A2", "A4", "B"]


def main():
    rows = list(csv.DictReader(CSV.open()))
    contexts = sorted({int(r["S_kv"]) for r in rows})
    fig, axes = plt.subplots(1, len(contexts), figsize=(6.5 * len(contexts), 4.5),
                             squeeze=False)
    xmax = max(int(r["B"]) for r in rows)  # largest SIP capacity (= 16)
    for col, S in enumerate(contexts):
        ax = axes[0][col]
        for m in MODES:
            pts = sorted(
                ((int(r["B"]), float(r["throughput_users_per_us"]))
                 for r in rows if r["mode"] == m and int(r["S_kv"]) == S),
                key=lambda t: t[0],
            )
            if not pts:
                continue
            xs, ys = zip(*pts)
            # Measured: concurrent users up to the SIP capacity 16/C.
            ax.plot(xs, ys, marker="o", color=MODE_COLOR[m],
                    label=MODE_LABEL[m])
            # Beyond capacity the SIP is full: extra users run in waves at
            # the saturated rate, so throughput plateaus. Draw that ceiling
            # as a dashed extension (projected, not concurrently measured).
            if xs[-1] < xmax:
                ax.plot([xs[-1], xmax], [ys[-1], ys[-1]],
                        linestyle="--", color=MODE_COLOR[m], alpha=0.55)
            ax.annotate(f"{ys[-1]:.2f}", (xs[-1], ys[-1]),
                        textcoords="offset points", xytext=(4, 4), fontsize=8)
        ax.set_title(f"S_kv = {S // 1024}K")
        ax.set_xlabel("batch size B (concurrent users)")
        ax.set_ylabel("throughput (requests / µs)")
        ax.grid(True, alpha=0.3)
        ax.legend(fontsize=9)
    fig.suptitle("Batch scaling: aggregate throughput vs concurrent users "
                 "(one SIP)", fontsize=12, fontweight="bold")
    fig.tight_layout()
    OUT.parent.mkdir(parents=True, exist_ok=True)
    fig.savefig(OUT, dpi=140, bbox_inches="tight")
    print(f"  ✓ {OUT}")


if __name__ == "__main__":
    main()
