Opens a larger view. Escape closes it.

hardware-counters

make_simple_figs.py

#!/usr/bin/env python3
"""
Two deliberately simple figures for the dissertation.

fig_ladder.png    the measurement ladder - the report's central result, which
                  currently exists only as a table. A log-scale horizontal bar
                  chart reads in about three seconds: two long bars (know
                  nothing), then a collapse to near-1 as soon as the cycle
                  count arrives, then almost nothing after.

fig_perapp.png    per-application error for the constant baseline against the
                  full counter model. Shows at a glance that the counters help
                  on five applications and hurt on three, which the report
                  states in prose but never displays.
"""
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np

OUT = "/tmp/figs"
import os; os.makedirs(OUT, exist_ok=True)

# ----------------------------------------------------------------- the ladder
rungs = [
    ("Predict the training median\n(measure nothing)",        7.588),
    ("Job configuration only\n(free metadata)",               7.826),
    ("Cycle count, assume no stalls\n(1 counter)",            1.238),
    ("Cycle count + fitted constant\n(1 counter)",            1.065),
    ("Cycle count + all 21 features\n(5 profiling runs)",     1.054),
]
labels = [r[0] for r in rungs]
vals   = [r[1] for r in rungs]

fig, ax = plt.subplots(figsize=(8.4, 4.0))
y = np.arange(len(vals))[::-1]
# grey for the two that know nothing useful, blue once the counter arrives
cols = ["0.72", "0.72", "#4477aa", "#4477aa", "#225588"]
ax.barh(y, vals, color=cols, height=0.62)
ax.axvline(1.0, color="k", lw=1.1)
ax.text(1.02, 4.62, "perfect", fontsize=8.5, va="center")

for yi, v in zip(y, vals):
    ax.text(v * 1.06, yi, f"{v:.3f}", va="center", fontsize=10)

ax.set_yticks(y); ax.set_yticklabels(labels, fontsize=9.5)
ax.set_xscale("log")
ax.set_xlim(0.9, 14)
ax.set_xticks([1, 2, 5, 10])
ax.set_xticklabels(["1x", "2x", "5x", "10x"])
ax.set_xlabel("typical error factor (1x is exact prediction)", fontsize=10)
ax.set_title("Almost all the accuracy arrives with the first counter",
             fontsize=11.5, pad=10)
ax.grid(axis="x", alpha=0.3)
for sp in ("top", "right"): ax.spines[sp].set_visible(False)
fig.tight_layout()
fig.savefig(f"{OUT}/fig_ladder.png", dpi=160)
plt.close(fig)
print("wrote fig_ladder.png")

# ------------------------------------------------------- per-application view
apps  = ["comd", "gromacs", "hpcg", "hpl", "lulesh", "minife", "openfoam", "stream"]
const = [1.046, 1.051, 1.048, 1.078, 1.175, 1.372, 1.068, 1.051]
rf    = [1.026, 1.006, 1.117, 1.043, 1.049, 1.067, 1.073, 1.099]

order = np.argsort(const)[::-1]
apps  = [apps[i] for i in order]
const = [const[i] for i in order]
rf    = [rf[i] for i in order]

fig, ax = plt.subplots(figsize=(8.4, 3.9))
x = np.arange(len(apps)); w = 0.38
ax.bar(x - w/2, [c - 1 for c in const], w, bottom=1,
       color="0.72", label="no counters (constant)")
ax.bar(x + w/2, [r - 1 for r in rf], w, bottom=1,
       color="#4477aa", label="all 21 counter features")
ax.axhline(1.0, color="k", lw=1.0)

for xi, (c, r) in enumerate(zip(const, rf)):
    ax.annotate("", xy=(xi + w/2, r), xytext=(xi - w/2, c),
                arrowprops=dict(arrowstyle="->", lw=0.9,
                                color="green" if r < c else "firebrick"))

ax.set_xticks(x); ax.set_xticklabels(apps, fontsize=10)
ax.set_ylabel("error factor", fontsize=10)
ax.set_ylim(1.0, 1.42)
ax.set_title("Counters help on five applications and hurt on three",
             fontsize=11.5, pad=10)
ax.legend(fontsize=9, frameon=False, loc="upper right")
ax.grid(axis="y", alpha=0.3)
for sp in ("top", "right"): ax.spines[sp].set_visible(False)
fig.tight_layout()
fig.savefig(f"{OUT}/fig_perapp.png", dpi=160)
plt.close(fig)
print("wrote fig_perapp.png")