#!/usr/bin/env python3
"""Sequence experiments: common then api, idle gap, QoS, cgu variants."""
import ctypes, json, os, subprocess, 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 = {"api_common": os.path.join(ROOT, "api-common/src/lib.rs"),
       "api": os.path.join(ROOT, "api/src/lib.rs")}
orig = {k: open(v).read() for k, v in SRC.items()}
INV = {k: json.load(open(os.path.join(REC, k + ".json"))) for k in SRC}

libc = ctypes.CDLL(None)
QOS_CLASS_USER_INTERACTIVE = 0x21
QOS_CLASS_USER_INITIATED = 0x19


def set_qos(cls):
    rc = libc.pthread_set_qos_class_self_np(ctypes.c_uint(cls), ctypes.c_int(0))
    return rc


def compile_(name, extra=()):
    inv = INV[name]
    started = time.monotonic()
    p = subprocess.run(list(inv["argv"]) + list(extra), cwd=inv["cwd"],
                       env=dict(inv["env"]), stdout=subprocess.DEVNULL,
                       stderr=subprocess.PIPE)
    elapsed = (time.monotonic() - started) * 1000
    if p.returncode != 0:
        raise SystemExit(p.stderr.decode()[:2000])
    return elapsed


def seq(common_extra=(), api_extra=(), gap=0.15, qos=None, n=8):
    if qos is not None:
        set_qos(qos)
    cs, as_ = [], []
    for i in range(n):
        open(SRC["api_common"], "w").write(orig["api_common"].replace("nested-v1", f"x-{time.time_ns()}"))
        time.sleep(gap)
        cs.append(compile_("api_common", common_extra))
        as_.append(compile_("api", api_extra))
    return cs, as_


def report(label, cs, as_):
    c, a = statistics.median(cs), statistics.median(as_)
    print(f"{label:40s} common={c:6.1f} api={a:6.1f} total={c + a:6.1f} "
          f"(min {min(cs) + min(as_):6.1f}, max {max(cs) + max(as_):6.1f})")


try:
    print("rc for USER_INTERACTIVE:", set_qos(QOS_CLASS_USER_INTERACTIVE))
    for qos, qlabel in ((None, "default-qos"), (QOS_CLASS_USER_INTERACTIVE, "qos=user-interactive"),
                        (QOS_CLASS_USER_INITIATED, "qos=user-initiated")):
        cs, as_ = seq(qos=qos)
        report(f"baseline cgu16 {qlabel}", cs, as_)
    set_qos(QOS_CLASS_USER_INTERACTIVE)
    for cg in (1, 2, 4, 8, 16, 32):
        cs, as_ = seq(common_extra=("-C", f"codegen-units={cg}"),
                      api_extra=("-C", f"codegen-units={cg}"))
        report(f"common+api cgu{cg} qos=UI", cs, as_)
    for cg in (4, 8, 16):
        cs, as_ = seq(common_extra=("-C", f"codegen-units={cg}"))
        report(f"common cgu{cg} only", cs, as_)
    for cg in (4, 8, 16):
        cs, as_ = seq(api_extra=("-C", f"codegen-units={cg}"))
        report(f"api cgu{cg} only", cs, as_)
    cs, as_ = seq(common_extra=("--emit=metadata,link",), api_extra=("--emit=metadata,link",))
    report("no dep-info", cs, as_)
finally:
    for k, v in SRC.items():
        open(v, "w").write(orig[k])
