#!/usr/bin/env python3
"""Summarize saved planner sweeps, including simultaneous placed address occupancy."""
import argparse
import json
from pathlib import Path


def union_bytes(ranges):
    end = 0
    total = 0
    for start, stop in sorted(ranges):
        total += max(0, stop - max(start, end))
        end = max(end, stop)
    return total


def placement_peaks(profile):
    # Placement JSON uses disjoint region-0/region-1 address ranges. Count
    # simultaneous unions: aliases must not count twice, nor successive users.
    peaks = {"all": 0, "tensors": 0, "support": 0}
    for tile in profile["tiles"]:
        allocations = [a for a in tile["allocations"]
                       if profile["labels"][a["label"]] != "Outside application load range"]
        for category in peaks:
            selected = [a for a in allocations if category == "all"
                        or (category == "support") == (a["kind"] == "support")]
            for step in {a["first"] for a in selected}:
                size = union_bytes((a["start"], a["end"]) for a in selected
                                   if a["first"] <= step <= a["last"])
                peaks[category] = max(peaks[category], size)
    return peaks


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("directories", type=Path, nargs="+")
    args = parser.parse_args()
    rows = []
    for directory in args.directories:
        for path in sorted(directory.glob("*/result.json")):
            result = json.loads(path.read_text())
            row = {k: result[k] for k in ("case", "status", "wall_seconds")}
            row["planning"] = result["stages"].get("construct_mid")
            row["cycles"] = result.get("renderer_cycles")
            for memory in path.parent.glob("memory/baseline-*.json"):
                data = json.loads(memory.read_text())
                row["estimated_tensor_bytes"] = data["peak"]["total"]
                row["estimated_rows_bytes"] = data["peak"]["exchange_rows"]
                row["estimated_with_support_bytes"] = data["effective_peak_bytes"]
            for memory in path.parent.glob("memory/placement-*.json"):
                row["placed_peaks_bytes"] = placement_peaks(json.loads(memory.read_text()))
            if result["diagnostic"]:
                row["error"] = "\n".join(result["diagnostic"][-5:])
            rows.append(row)
    print(json.dumps(rows, indent=2))


if __name__ == "__main__":
    main()
