#!/usr/bin/env python3
"""Summarize vLLM scheduler prefix-cache `computed:` log lines."""

from __future__ import annotations

import argparse
import json
import re
from pathlib import Path
from typing import Any


START_RE = re.compile(r"Request (\d+) started running, prompt: (\d+), computed: (\d+)")
PREEMPT_RE = re.compile(r"Request (\d+) preempted")


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description=(
            "Parse vLLM scheduler logs and report observed computed-token "
            "prefix-cache behavior. Repeated starts indicate preemption or "
            "re-admission, so all-start sums are not equivalent to per-request "
            "prefix hits."
        )
    )
    parser.add_argument("stdout_log", type=Path)
    parser.add_argument("--summary-json", type=Path)
    return parser.parse_args()


def load_estimated_hit_tokens(path: Path | None) -> int | None:
    if path is None:
        return None
    summary = json.loads(path.read_text(encoding="utf-8"))
    reuse = summary.get("estimated_prefix_reuse", {})
    hit_tokens = reuse.get("hit_tokens")
    return int(hit_tokens) if hit_tokens is not None else None


def main() -> int:
    args = parse_args()
    text = args.stdout_log.read_text(encoding="utf-8", errors="replace")

    by_request: dict[int, list[dict[str, int]]] = {}
    for match in START_RE.finditer(text):
        request_id = int(match.group(1))
        by_request.setdefault(request_id, []).append(
            {
                "prompt_tokens": int(match.group(2)),
                "computed_tokens": int(match.group(3)),
            }
        )

    preempted_request_ids = [int(match.group(1)) for match in PREEMPT_RE.finditer(text)]
    repeated = {
        str(request_id): starts
        for request_id, starts in sorted(by_request.items())
        if len(starts) > 1
    }

    all_computed = sum(
        start["computed_tokens"]
        for starts in by_request.values()
        for start in starts
    )
    first_computed = sum(starts[0]["computed_tokens"] for starts in by_request.values())
    last_computed = sum(starts[-1]["computed_tokens"] for starts in by_request.values())
    max_computed = sum(max(start["computed_tokens"] for start in starts) for starts in by_request.values())
    estimated_hit_tokens = load_estimated_hit_tokens(args.summary_json)

    result: dict[str, Any] = {
        "stdout_log": str(args.stdout_log),
        "starts_total": sum(len(starts) for starts in by_request.values()),
        "unique_requests": len(by_request),
        "preemptions": len(preempted_request_ids),
        "preempted_request_ids": preempted_request_ids,
        "repeated_request_ids": sorted(int(request_id) for request_id in repeated),
        "computed_tokens": {
            "all_starts": all_computed,
            "first_start_per_request": first_computed,
            "last_start_per_request": last_computed,
            "max_per_request": max_computed,
        },
        "repeated_starts": repeated,
    }
    if estimated_hit_tokens is not None:
        result["estimated_prefix_hit_tokens"] = estimated_hit_tokens
        result["matches_estimate"] = {
            name: value == estimated_hit_tokens
            for name, value in result["computed_tokens"].items()
        }

    print(json.dumps(result, indent=2, sort_keys=True))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
