Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
Python
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101#!/usr/bin/env python3"""Per-phase CPU use of one batch run: how long each phase took and how many CPUs itkept busy, from bench/cpu-sample.sh's samples and the run's own phase markers.
bench/cpu-phases.py <cpu.tsv> <phases.tsv> [<run.stamped.log>]
<cpu.tsv> is bench/cpu-sample.sh's output ("<unix time> <busy CPUs>" per sample).<phases.tsv> has one "<unix time> <phase>" line per phase start, written by the batchscript; a phase runs until the next line, and a last line "end" closes the run.<run.stamped.log>, if given, is the model-run binary's output with a unix time before eachline; its batch headers and "timing:" lines split the script's model-run phase intodraw (waiting on the model), probe (compiling each candidate on its own), scoring-build(compiling the survivors as one crate), scoring-run (running them over the corpus) andconclude (everything else in the binary: reports, admission, the next prompt).
Prints one row per phase name, summed over every occurrence: wall seconds, CPU-seconds,average busy CPUs (CPU-seconds over wall seconds) and the peak single sample. Samples areattributed by their end time, so a phase shorter than the sampling interval can show nosamples. With a mixed-model batch, shares overlap and the split of the model run is onlyapproximate."""
import reimport sys
SUB_PHASES = [ (re.compile(r"^===== batch "), "draw"), (re.compile(r"^timing: .*: drew "), "probe"), (re.compile(r"^timing: .*: probed "), "scoring-build"), (re.compile(r"^timing: .*: built the scoring crate "), "scoring-run"), (re.compile(r"^timing: .*: scored "), "conclude"),]
def read_pairs(path): out = [] with open(path) as f: for line in f: parts = line.rstrip("\n").split(" ", 1) if len(parts) == 2: try: out.append((float(parts[0]), parts[1])) except ValueError: pass return out
def main(): if len(sys.argv) not in (3, 4): print(__doc__, file=sys.stderr) sys.exit(2) samples = [(t, float(v)) for t, v in read_pairs(sys.argv[1])] events = read_pairs(sys.argv[2]) if len(sys.argv) == 4: # Split every "model-run" span by the binary's own markers. runs = [(t, i) for i, (t, name) in enumerate(events) if name == "model-run"] extra = [] for t, line in read_pairs(sys.argv[3]): for pattern, name in SUB_PHASES: if pattern.search(line): extra.append((t, name)) break if runs and extra: events = sorted(events + extra, key=lambda e: e[0]) events.sort(key=lambda e: e[0])
spans = [] for (t0, name), (t1, _) in zip(events, events[1:]): if name != "end": spans.append((name, t0, t1))
order, stats = [], {} for name, t0, t1 in spans: if name not in stats: order.append(name) stats[name] = {"wall": 0.0, "cpu": 0.0, "peak": 0.0, "n": 0} s = stats[name] s["wall"] += t1 - t0 prev = None for t, busy in samples: if prev is not None and t0 < t <= t1: s["cpu"] += busy * (t - prev) s["peak"] = max(s["peak"], busy) s["n"] += 1 prev = t
total_wall = sum(s["wall"] for s in stats.values()) total_cpu = sum(s["cpu"] for s in stats.values()) peak = max((s["peak"] for s in stats.values()), default=0.0) print(f"{'phase':<14} {'wall s':>8} {'CPU s':>9} {'avg busy':>9} {'peak busy':>10} {'samples':>8}") for name in order: s = stats[name] avg = s["cpu"] / s["wall"] if s["wall"] else 0.0 print(f"{name:<14} {s['wall']:>8.1f} {s['cpu']:>9.1f} {avg:>9.1f} {s['peak']:>10.1f} {s['n']:>8}") avg = total_cpu / total_wall if total_wall else 0.0 print(f"{'whole run':<14} {total_wall:>8.1f} {total_cpu:>9.1f} {avg:>9.1f} {peak:>10.1f}")
if __name__ == "__main__": main()