Opens a larger view. Escape closes it.

hardware-counters

rapl_check.py

"""
Is PACKAGE_ENERGY per-rank or per-node?

An agent inferred it is per-rank, because average power reads 81 W at one core
and 1.9 W at 128, which is physically impossible for a package with a 225 W
nameplate TDP. If true, every energy conclusion flips: the uncorrected reading
makes the largest core count look energy-optimal in almost every case, the
corrected one does not. Test the inference directly.
"""
import os
import numpy as np, pandas as pd

D = os.environ.get("DISS_ROOT", "/work/project/project/user")
df = pd.read_csv(f"{D}/data/runs_expanded.csv")
df = df[(df.runtime_s > 0) & df.PACKAGE_ENERGY.notna()]

keys = ["app", "size", "ncore", "nthread", "nrank"]
m = df.groupby(keys, as_index=False).agg(
    PACKAGE_ENERGY=("PACKAGE_ENERGY", "median"),
    PP0_ENERGY=("PP0_ENERGY", "median"),
    runtime_s=("runtime_s", "median"))

m["power_raw"] = m.PACKAGE_ENERGY / m.runtime_s
m["power_x_nrank"] = m.power_raw * m.nrank

print("average power (J/s) by core count, as recorded vs scaled by nrank")
print(f"{'ncore':>6} {'n':>4} {'raw W':>9} {'x nrank W':>11}")
print("-" * 34)
for nc, g in m.groupby("ncore"):
    print(f"{int(nc):>6} {len(g):>4} {g.power_raw.median():9.1f} "
          f"{g.power_x_nrank.median():11.1f}")

print("\nEPYC 7742 nameplate TDP = 225 W per socket, 2 sockets/node = 450 W.")
print("A plausible per-node reading rises with core count and stays under that.")
print("A per-rank reading falls as ~C/nrank.")

fit = (m.power_raw * m.nrank).median()
resid = (m.power_raw - fit / m.nrank).abs() / m.power_raw
print(f"\nfit of raw power to C/nrank with C={fit:.1f}: "
      f"median relative residual {resid.median()*100:.1f}%")
print("(a small residual means the raw column really is a per-rank quantity)")

print("\nPP0 as a fraction of PACKAGE (should be roughly 0.5-0.9 for a busy CPU):")
r = (m.PP0_ENERGY / m.PACKAGE_ENERGY).replace([np.inf, -np.inf], np.nan).dropna()
print(f"  median {r.median():.4f}   IQR {r.quantile(.25):.4f}-{r.quantile(.75):.4f}")

print("\nquantisation: are the raw joule values integers?")
raw = pd.to_numeric(df.PACKAGE_ENERGY, errors="coerce").dropna()
print(f"  {100*(raw == raw.round()).mean():.1f}% of {len(raw)} raw rows are whole numbers")
print(f"  values <= 5 J: {int((raw <= 5).sum())} rows "
      f"(where +-0.5 J rounding is a large relative error)")