interaction_probe.py
import os
import numpy as np, pandas as pd
D = os.environ.get("DISS_ROOT", "/work/project/project/user")
KEYS = ["app", "size", "ncore", "nthread"]
CTR = ["PAPI_TOT_CYC", "PAPI_TOT_INS", "PAPI_FP_OPS", "PAPI_L1_DCA",
"PAPI_L2_DCM", "PAPI_L2_DCH", "PAPI_TLB_DM", "UNC_L3_CACHE_MISSES",
"UNC_L3_MISS_LATENCY",
"DISPATCH_RESOURCE_STALL_CYCLES_1:LOAD_QUEUE_RSRC_STALL",
"DISPATCH_RESOURCE_STALL_CYCLES_1:STORE_QUEUE_RSRC_STALL"]
def merge(path):
df = pd.read_csv(path)
df = df[df.runtime_s > 0]
agg = {c: "median" for c in CTR if c in df.columns}
agg["runtime_s"] = "median"
return df.groupby(KEYS, as_index=False).agg(agg)
A, C = merge(f"{D}/data/runs_expanded.csv"), merge(f"{D}/data/cirrus_persets.csv")
m = pd.merge(A, C, on=KEYS, suffixes=("_a2", "_cir")).dropna(subset=["runtime_s_a2",
"runtime_s_cir"])
m["speedup"] = m.runtime_s_a2 / m.runtime_s_cir
m["log_speedup"] = np.log2(m.speedup)
print(f"matched configurations: {len(m)}, apps: {m.app.nunique()}\n")
g = lambda c: pd.to_numeric(m.get(f"{c}_a2"), errors="coerce")
cyc, ins = g("PAPI_TOT_CYC"), g("PAPI_TOT_INS")
sig = pd.DataFrame({
"ipc": ins / cyc,
"flops_per_instr": g("PAPI_FP_OPS") / ins,
"l2_miss_per_instr": g("PAPI_L2_DCM") / ins,
"l2_hit_rate": g("PAPI_L2_DCH") / (g("PAPI_L2_DCH") + g("PAPI_L2_DCM")),
"l3_miss_per_instr": g("UNC_L3_CACHE_MISSES") / ins,
"l3_lat_per_miss": g("UNC_L3_MISS_LATENCY") / g("UNC_L3_CACHE_MISSES"),
"tlb_miss_per_instr": g("PAPI_TLB_DM") / ins,
"stall_load_frac": g("DISPATCH_RESOURCE_STALL_CYCLES_1:LOAD_QUEUE_RSRC_STALL") / cyc,
"stall_store_frac": g("DISPATCH_RESOURCE_STALL_CYCLES_1:STORE_QUEUE_RSRC_STALL") / cyc,
"arith_intensity": g("PAPI_FP_OPS") / (g("UNC_L3_CACHE_MISSES") * 64.0),
"log_ncore": np.log2(m.ncore),
}).replace([np.inf, -np.inf], np.nan)
print("correlation of each SOURCE-machine signature feature with log2(speedup)")
print("pooled over all configurations, and averaged within application")
print(f"{'feature':20s} {'pooled r':>9s} {'within-app r':>13s} {'n':>5s}")
print("-" * 52)
res = []
for c in sig.columns:
v = sig[c]
ok = v.notna() & m.log_speedup.notna()
if ok.sum() < 30:
continue
r_pool = np.corrcoef(v[ok], m.log_speedup[ok])[0, 1]
parts = []
for a, gg in m[ok].groupby("app"):
vv = sig.loc[gg.index, c]
if vv.notna().sum() > 5 and vv.std() > 0 and gg.log_speedup.std() > 0:
parts.append(np.corrcoef(vv, gg.log_speedup)[0, 1])
r_within = np.nanmean(parts) if parts else np.nan
res.append((c, abs(r_pool)))
print(f"{c:20s} {r_pool:+9.3f} {r_within:+13.3f} {int(ok.sum()):5d}")
print("\nstrongest pooled predictors of speedup:")
for c, r in sorted(res, key=lambda x: -x[1])[:4]:
print(f" {c} (|r| = {r:.3f})")
print("\n=== how much of the speedup is 'which application'? ===")
ss_tot = ((m.log_speedup - m.log_speedup.mean()) ** 2).sum()
ss_res = sum(((gg.log_speedup - gg.log_speedup.mean()) ** 2).sum()
for _, gg in m.groupby("app"))
print(f" application identity explains {100*(1-ss_res/ss_tot):.1f}% of log2(speedup) variance")
print(f" the remaining {100*ss_res/ss_tot:.1f}% is within-application "
f"(problem size and core count)")
print("\nIf application identity dominates, a model must infer the per-app")
print("response from the signature, which is exactly the LOAO test.")