mariadb-haskell-0.1.0.0: validation/profile_workloads.py
#!/usr/bin/env python3
"""Run focused experiments using the unchanged frozen workload functions.
These development measurements never replace the complete live report. A failed
build/workload or a source edit during measurement invalidates the experiment.
"""
import argparse
import json
import os
from pathlib import Path
import statistics
import publish_results as live
import release_recorder as run
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--profiles", nargs="+", required=True)
parser.add_argument("--repetitions", type=int, default=7)
parser.add_argument("--output", type=Path, required=True)
args = parser.parse_args()
if args.repetitions < 1:
parser.error("repetitions must be positive")
if args.output.exists():
parser.error("experiment exists; preserve previous results")
env = os.environ.copy()
env.update(json.loads((run.HERE / ".local/environment.json").read_text()))
env["TZ"] = "UTC"
print("MariaDB:", run.sql_client(env, "SELECT VERSION()"), flush=True)
inputs = live.input_snapshot()
# run.command checks exit status: never measure a stale binary after a
# failed build. Keep the build log beside the separate experiment output.
build = run.command(
["cabal", "build", "exe:mariadb-validation", "-O2", "--enable-tests"],
timeout=300,
)
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.with_suffix(".build.log").write_text(build.stdout + build.stderr)
if live.input_snapshot()["files"] != inputs["files"]:
raise RuntimeError("inputs changed during profile build")
binary = run.executable("exe:mariadb-validation")
manifest = dict(
line.split("\t")
for line in run.command([binary, "list-benchmarks"]).stdout.splitlines()
)
unknown = set(args.profiles) - manifest.keys()
if unknown:
parser.error("unknown frozen workloads: " + ", ".join(sorted(unknown)))
data = {
"schema": 1,
"recorded_at": live.now(),
"inputs": inputs,
"successful_fresh_build": True,
"server": run.server_metadata(env),
"profiles": {},
}
logs = args.output.with_suffix("")
logs.mkdir()
for ident in args.profiles:
samples = [
run.benchmark_sample(
binary, ident, int(manifest[ident]), env,
logs / f"{ident}.{rep}.log",
)
for rep in range(args.repetitions)
]
if any(sample["status"] != "PASS" for sample in samples):
raise RuntimeError("workload failed: " + ident)
profile = {
"samples": samples,
"median_ns_per_unit": statistics.median(
sample["ns_per_unit"] for sample in samples
),
"median_allocated_bytes_per_unit": statistics.median(
sample["allocated_bytes"] / sample["units"] for sample in samples
),
}
data["profiles"][ident] = profile
print(ident, profile["median_ns_per_unit"],
profile["median_allocated_bytes_per_unit"], flush=True)
if live.input_snapshot()["files"] != inputs["files"]:
raise RuntimeError("inputs changed during profile experiment")
args.output.write_text(json.dumps(data, indent=2) + "\n")
if __name__ == "__main__":
main()