parse_expand.py
import os, re, subprocess, csv, sys
from pathlib import Path
PR = "/opt/cray/pe/perftools/23.09.0/bin/pat_report"
D = os.environ.get("DISS_ROOT", "/work/project/project/user")
ROOT = Path(f"{D}/runs")
OUT = Path(f"{D}/data")
VAL = re.compile(r"^ (?P<n>[A-Z][A-Za-z0-9_:]*)\s+"
r"(?:(?:[\d.]+)\s*(?:[GMK]/sec|W)\s+)?"
r"(?P<v>\d[\d,]*(?:\.\d+)?)\s*"
r"(?:ops|instr|cycles|J|refs|misses|hits)?\s*$")
TIME = re.compile(r"^ Thread Time\s+([\d.]+)\s+secs")
ORIG_SIZE = {"stream": 80000000, "hpcg": 32, "hpl": 0,
"gromacs": 0, "openfoam": 100}
def parse(exp):
try:
out = subprocess.run([PR, "-O", "hwpc", str(exp)],
capture_output=True, text=True, timeout=600).stdout
except Exception:
return None, {}
vals, t = {}, None
for line in out.splitlines():
if "PAT_RT_PERFCTR" in line:
break
mt = TIME.match(line)
if mt:
t = float(mt.group(1)); continue
m = VAL.match(line)
if m and m.group("n") not in ("Thread", "Total"):
try:
vals[m.group("n")] = float(m.group("v").replace(",", ""))
except ValueError:
pass
return t, vals
rows = []
def harvest(d, app, ncore, size, nthread, campaign):
for s in "ABCDE":
exp = d / f"exp_{s}"
if not exp.exists():
continue
t, vals = parse(exp)
if t is None or not vals:
continue
rows.append({"app": app, "ncore": ncore, "size": size,
"nthread": nthread, "nrank": ncore // max(nthread, 1),
"cset": s, "campaign": campaign,
"runtime_s": t, **vals})
for d in sorted((ROOT / "expand").glob("*_c*_s*_t*")):
m = re.match(r"([a-z]+)_c(\d+)_s(\d+)_t(\d+)$", d.name)
if not m or not d.is_dir():
continue
harvest(d, m.group(1), int(m.group(2)), int(m.group(3)),
int(m.group(4)), "expand")
print(f"expand {d.name}", file=sys.stderr)
for d in sorted((ROOT / "sweep").glob("*_c*")):
m = re.match(r"([a-z0-9]+)_c(\d+)$", d.name)
if not m or not d.is_dir():
continue
app, nc = m.group(1), int(m.group(2))
if app == "cp2k":
continue
harvest(d, app, nc, ORIG_SIZE.get(app, 0), 1, "orig")
print(f"orig {d.name}", file=sys.stderr)
lead = ["app", "campaign", "ncore", "nthread", "nrank", "size", "cset", "runtime_s"]
keys = lead + sorted({k for r in rows for k in r} - set(lead))
OUT.mkdir(parents=True, exist_ok=True)
with open(OUT / "runs_expanded.csv", "w", newline="") as fh:
w = csv.DictWriter(fh, fieldnames=keys)
w.writeheader(); w.writerows(rows)
print(f"\nwrote runs_expanded.csv: {len(rows)} rows x {len(keys)} cols")
from collections import Counter
print("by app:", dict(Counter(r["app"] for r in rows)))