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
|
#!/usr/bin/env python3
"""
Read any percentile out of the raw lazy/super-lazy-eval histograms
persisted by eval.c's _PersistRawHistogramsToFile (called automatically
every time a DUMP_RESIDUAL_SAMPLES build runs `calibrate residual`).
Usage:
python3 hist_percentile.py <histograms_file> [percentiles...]
python3 hist_percentile.py residual_raw_histograms_guess2_30k.txt
python3 hist_percentile.py residual_raw_histograms_guess2_30k.txt 0.93 0.97 0.985
With no percentile arguments, prints a default useful spread for every
bucket of all three histograms (residual, sl_residual, king). With
percentile arguments (0.0-1.0), prints just those, letting you probe
any exact percentile the fixed comment-block charts in eval.c didn't
happen to include -- no re-running the 30k pool required, as long as
this file (or a fresher one) still exists.
File format (one line per histogram/bucket):
<name> <bucket 0-7> <min> <max> <bin0-count> <bin1-count> ... <binN-1-count>
Bin i covers [RESID_HIST_MIN + i*RESID_HIST_BIN_WIDTH,
RESID_HIST_MIN + (i+1)*RESID_HIST_BIN_WIDTH).
These constants are echoed in the file's own header comment and also
hardcoded below (must match eval.c's #defines -- they haven't changed
since this was built, but check if eval.c's RESID_HIST_* macros ever
do).
"""
import sys
BIN_WIDTH = 20
MIN_VAL = -900
DEFAULT_PERCENTILES = [0.01, 0.02, 0.05, 0.10, 0.15, 0.50,
0.85, 0.90, 0.95, 0.98, 0.99]
def load(path):
hists = {}
with open(path) as f:
for line in f:
if line.startswith('#') or not line.strip():
continue
parts = line.split()
name, bucket = parts[0], int(parts[1])
mn, mx = int(parts[2]), int(parts[3])
bins = list(map(int, parts[4:]))
hists[(name, bucket)] = (mn, mx, bins)
return hists
def percentile(bins, total, p):
target = p * total
running = 0
for i, c in enumerate(bins):
running += c
if running >= target:
return MIN_VAL + i * BIN_WIDTH + BIN_WIDTH // 2
return MIN_VAL + len(bins) * BIN_WIDTH
def main():
if len(sys.argv) < 2:
print(__doc__)
sys.exit(1)
path = sys.argv[1]
percentiles = [float(x) for x in sys.argv[2:]] or DEFAULT_PERCENTILES
hists = load(path)
names = sorted(set(name for name, _ in hists.keys()))
for name in names:
print(f"--- {name} ---")
for b in range(8):
if (name, b) not in hists:
continue
mn, mx, bins = hists[(name, b)]
total = sum(bins)
if total == 0:
print(f" bucket {b}: no samples")
continue
vals = " ".join(f"p{p*100:g}={percentile(bins, total, p)}"
for p in percentiles)
print(f" bucket {b}: n={total} min={mn} {vals} max={mx}")
if __name__ == "__main__":
main()
|