#!/usr/bin/env python3
"""Interleaved A/B of idle-wake mitigations."""
import json, os, subprocess, threading, time, statistics

REC = "/Users/oscar/.worktree/hot-reload/labs/hot-reload/target/kan-hot/debug/rustc"
ROOT = "/Users/oscar/.worktree/hot-reload/labs/hot-reload"
SRC = os.path.join(ROOT, "api-common/src/lib.rs")
orig = open(SRC).read()
inv = json.load(open(os.path.join(REC, "api_common.json")))

spinner = threading.Event()


def spin_thread(duty_ms, period_ms):
    while not spinner.is_set():
        end = time.monotonic() + duty_ms / 1000
        while time.monotonic() < end:
            pass
        time.sleep(period_ms / 1000)


threads = []


def start_spinner(duty_ms, period_ms):
    spinner.clear()
    t = threading.Thread(target=spin_thread, args=(duty_ms, period_ms), daemon=True)
    t.start()
    threads.append((t, duty_ms, period_ms))


def stop_spinners():
    spinner.set()
    for t, _, _ in threads:
        t.join()
    threads.clear()


def compile_(prefix=()):
    open(SRC, "w").write(orig.replace("nested-v1", f"x-{time.time_ns()}"))
    time.sleep(0.15)
    started = time.monotonic()
    p = subprocess.run(list(prefix) + list(inv["argv"]), cwd=inv["cwd"],
                       env=dict(inv["env"]), stdout=subprocess.DEVNULL,
                       stderr=subprocess.PIPE)
    elapsed = (time.monotonic() - started) * 1000
    assert p.returncode == 0, p.stderr.decode()[:2000]
    return elapsed


variants = {
    "default": ((), False),
    "taskpolicy -l 0": (("taskpolicy", "-l", "0"), False),
    "taskpolicy -t 0": (("taskpolicy", "-t", "0"), False),
    "spinner 1ms/10ms": ((), True),
    "spinner 100%": ((), "full"),
}
try:
    results = {name: [] for name in variants}
    for round_ in range(6):
        for name, (prefix, spin) in variants.items():
            stop_spinners()
            if spin == "full":
                start_spinner(1000, 0)
            elif spin:
                start_spinner(1, 10)
            results[name].append(compile_(prefix))
    stop_spinners()
    for name, times in results.items():
        print(f"{name:24s} median={statistics.median(times):6.1f} mean={statistics.mean(times):6.1f} "
              f"min={min(times):6.1f} max={max(times):6.1f} all={[round(t,1) for t in times]}")
finally:
    stop_spinners()
    open(SRC, "w").write(orig)
