Opens a larger view. Escape closes it.

hardware-counters

weak_sizes.py

#!/usr/bin/env python3
"""
Weak-scaling problem sizes: keep work PER RANK roughly constant so runtime
stays in a useful 10-60 s window as core count grows.

Motivation (see analysis/size_diag.py): with fixed global sizes on a 288-core
Cirrus node, miniFE was 90.5% sub-second, HPL 65%, CoMD 64%. Below ~1 s the
fixed overheads (MPI_Init, I/O, CrayPat instrumentation) dominate wall time and
the efficiency factor collapses, so the counters cannot explain runtime.

Scaling rules, by how each benchmark's size knob is defined:
  miniFE  nx=ny=nz is a GLOBAL 3D grid  -> nx ~ base * cbrt(nranks)
  CoMD    -x -y -z is a GLOBAL lattice  -> x  ~ base * cbrt(nranks)
  HPL     N is the GLOBAL matrix order  -> N  ~ base * sqrt(nranks)
          (work is O(N^3), memory O(N^2); sqrt keeps memory/rank constant)
  STREAM  array length is global        -> len ~ base * nranks
  HPCG    nx/ny/nz are ALREADY per-rank -> keep fixed, just raise the base
  LULESH  -s is ALREADY per-rank        -> keep fixed, just raise the base

usage: weak_sizes.py APP NRANK BASE
"""
import sys

app, nrank, base = sys.argv[1], int(sys.argv[2]), int(sys.argv[3])
n = max(nrank, 1)

if app in ("minife", "comd"):
    v = int(round(base * n ** (1.0 / 3.0)))
    v = max(8, (v // 4) * 4)                 # keep it a tidy multiple of 4
elif app == "hpl":
    v = int(round(base * n ** 0.5))
    v = max(1000, (v // 192) * 192)          # multiple of the block size NB=192
elif app == "stream":
    v = base * n
    v = min(v, 400_000_000)                  # cap: memory per node
elif app in ("hpcg", "lulesh"):
    v = base                                 # already per-rank
else:
    v = base

print(v)