igneum/tools/attack/f9-grind/pod/join-power.py
2026-10-07 10:02:44 +00:00

55 lines
2 KiB
Python

#!/usr/bin/env python3
"""Attribute the 1-s nvidia-smi samples (epoch_ms power_w, sm_mhz, mem_mhz, temp_c, util) to the host log's phases."""
import sys
from collections import defaultdict
host, power = sys.argv[1], sys.argv[2]
phases = []
for line in open(host):
f = line.split()
if len(f) >= 14 and f[0] == "phase":
d = dict(zip(f[2::2], f[3::2]))
phases.append((f[1], int(d["round"]), int(d["start_ms"]), int(d["end_ms"]), float(d["MHs"])))
samples = []
for line in open(power):
f = line.replace(",", " ").split()
if len(f) < 6:
continue
try:
samples.append((int(f[0]), float(f[1]), float(f[2]), float(f[3]), float(f[4]), float(f[5])))
except ValueError:
pass
agg = defaultdict(list)
print("phase\tround\tsamples\tmean_W\tsm_MHz\tmem_MHz\ttemp_C\tutil\tMH/s\tMH/J")
for name, r, s, e, mhs in phases:
# drop the first second of each window (the sampler lags the launch)
rows = [x for x in samples if s + 1000 <= x[0] <= e]
if not rows:
print(f"{name}\t{r}\t0")
continue
w = sum(x[1] for x in rows) / len(rows)
sm = sum(x[2] for x in rows) / len(rows)
mem = sum(x[3] for x in rows) / len(rows)
t = sum(x[4] for x in rows) / len(rows)
u = sum(x[5] for x in rows) / len(rows)
agg[name].append((w, mhs))
print(f"{name}\t{r}\t{len(rows)}\t{w:.1f}\t{sm:.0f}\t{mem:.0f}\t{t:.0f}\t{u:.0f}\t{mhs:.3f}\t{mhs / w:.5f}")
print()
print("variant\trounds\tmean_W\tmean_MH/s\tMH/J\trel_rate_vs_honest\trel_MH/J_vs_honest")
base = None
for name in [p[0] for p in phases]:
if name in agg and name not in [b[0] for b in (base or [])]:
pass
order = []
for p in phases:
if p[0] not in order:
order.append(p[0])
ref = None
for name in order:
rows = agg[name]
w = sum(x[0] for x in rows) / len(rows)
m = sum(x[1] for x in rows) / len(rows)
eff = m / w
if ref is None:
ref = (m, eff)
print(f"{name}\t{len(rows)}\t{w:.1f}\t{m:.3f}\t{eff:.5f}\t{100 * (m - ref[0]) / ref[0]:+.3f}%\t{100 * (eff - ref[1]) / ref[1]:+.3f}%")