phase4-quantum-compression / src /energy /energy_logger_nvml.py
jmurray10's picture
Phase 4: Quantum-ML compression models and benchmarks
bc6498b verified
#!/usr/bin/env python3
# energy_logger_nvml.py
import argparse, csv, json, os, shlex, subprocess, sys, threading, time
try:
from pynvml import nvmlInit, nvmlShutdown, nvmlDeviceGetCount, nvmlDeviceGetHandleByIndex, nvmlDeviceGetPowerUsage
NVML_OK = True
except Exception:
NVML_OK = False
class _Sampler(threading.Thread):
def __init__(self, interval=0.1):
super().__init__(daemon=True)
self.interval = interval
self.samples = []
self.running = False
def run(self):
if not NVML_OK: return
nvmlInit()
try:
n = nvmlDeviceGetCount()
handles = [nvmlDeviceGetHandleByIndex(i) for i in range(n)]
self.running = True
while self.running:
t = time.time()
w = 0.0
for h in handles:
w += nvmlDeviceGetPowerUsage(h)/1000.0
self.samples.append((t, w))
time.sleep(self.interval)
finally:
try: nvmlShutdown()
except: pass
def stop(self): self.running = False
def _trapz(samples):
if len(samples) < 2: return 0.0
E = 0.0
for (t0,p0),(t1,p1) in zip(samples, samples[1:]):
E += 0.5*(p0+p1)*(t1-t0)
return E
class EnergyLogger:
def __init__(self, tag="session", interval=0.1, out_dir="energy_logs"):
self.tag = tag; self.interval=interval; self.out_dir=out_dir
self.sampler=_Sampler(interval=interval); self.t0=None; self.t1=None; self.summary={}
def __enter__(self):
os.makedirs(self.out_dir, exist_ok=True)
self.t0 = time.time(); self.sampler.start(); return self
def __exit__(self, *args):
self.sampler.stop(); self.sampler.join(); self.t1 = time.time()
dur = self.t1 - self.t0; E = _trapz(self.sampler.samples); avg = (E/dur) if dur>0 else 0.0
self.summary = {"duration_s": dur, "energy_J": E, "avg_power_W": avg, "samples": len(self.sampler.samples)}
def samples(self): return list(self.sampler.samples)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--cmd", type=str, required=True)
ap.add_argument("--interval", type=float, default=0.1)
ap.add_argument("--tag", type=str, default="session")
ap.add_argument("--out_dir", type=str, default="energy_logs")
args = ap.parse_args()
if not NVML_OK:
print(json.dumps({"error":"NVML not available; pip install pynvml and ensure NVIDIA driver present."}, indent=2)); sys.exit(2)
el = EnergyLogger(tag=args.tag, interval=args.interval, out_dir=args.out_dir)
with el:
import shlex, subprocess
proc = subprocess.Popen(shlex.split(args.cmd))
ret = proc.wait()
print(json.dumps({"returncode":ret, **el.summary}, indent=2)); sys.exit(ret)
if __name__ == "__main__":
main()