summaryrefslogtreecommitdiff
path: root/src/eval_tune/lazy_eval_margins/aggregate_marginsafety_shards.py
blob: 69e5c8ee606ec00537145a6515feaa3eec8c20de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/usr/bin/env python3
"""Combine N shards' persisted raw swing histograms (eval.c's
PersistMarginSafetyHistogramsToFile, "calibrate marginsafety <path>")
into one true aggregate: sum count/exceeded/sum/sumSq/histogram bins
bucket-by-bucket across all shard files, then recompute mean/stdev/
percentiles from the combined totals. Percentiles/means from
individual shards can't be validly averaged -- this reads raw counts
only and derives every statistic fresh from the combined totals.

Usage:
    python3 aggregate_marginsafety_shards.py <shard_file> [<shard_file> ...]
"""
import sys
from collections import defaultdict

BIN_WIDTH = 10


def load(path):
    """Yield (tier, bucket, count, exceeded, sum_, sumsq, max_, bins)."""
    with open(path) as f:
        for line in f:
            if line.startswith('#') or not line.strip():
                continue
            parts = line.split()
            tier, bucket = parts[0], int(parts[1])
            count, exceeded, sum_, sumsq, max_ = map(int, parts[2:7])
            bins = list(map(int, parts[7:]))
            yield tier, bucket, count, exceeded, sum_, sumsq, max_, bins


def percentile(bins, total, p):
    target = p * total
    running = 0
    for i, c in enumerate(bins):
        running += c
        if running >= target:
            return i * BIN_WIDTH + BIN_WIDTH // 2
    return (len(bins) - 1) * BIN_WIDTH


def main():
    if len(sys.argv) < 2:
        print(__doc__)
        sys.exit(1)

    agg = defaultdict(lambda: {"count": 0, "exceeded": 0, "sum": 0,
                                "sumsq": 0, "max": 0})
    agg_bins = {}

    for path in sys.argv[1:]:
        for tier, bucket, count, exceeded, sum_, sumsq, max_, bins in load(path):
            key = (tier, bucket)
            a = agg[key]
            a["count"] += count
            a["exceeded"] += exceeded
            a["sum"] += sum_
            a["sumsq"] += sumsq
            a["max"] = max(a["max"], max_)
            if key not in agg_bins:
                agg_bins[key] = bins[:]
            else:
                for i, c in enumerate(bins):
                    agg_bins[key][i] += c

    for tier in ("lazy", "superlazy"):
        print(f"--- {tier} ---")
        for bucket in range(8):
            key = (tier, bucket)
            if key not in agg:
                continue
            a = agg[key]
            n = a["count"]
            if n == 0:
                print(f"  bucket {bucket}: no exits taken")
                continue
            mean = a["sum"] / n
            variance = max(0.0, a["sumsq"] / n - mean * mean)
            stdev = variance ** 0.5
            pct = 100.0 * a["exceeded"] / n
            bins = agg_bins[key]
            p10 = percentile(bins, n, 0.10)
            p50 = percentile(bins, n, 0.50)
            p90 = percentile(bins, n, 0.90)
            p99 = percentile(bins, n, 0.99)
            print(f"  bucket {bucket}: n={n} exceeded={a['exceeded']} "
                  f"({pct:.3f}%)  max={a['max']} avg={mean:.1f} "
                  f"stdev={stdev:.1f}  p10={p10} p50={p50} p90={p90} p99={p99}")


if __name__ == "__main__":
    main()