codexfully-associative-lru-read-trace.py
fully-associative-lru-read-trace.py
"""Draw an exact synthetic read trace, including resident slots and LRU order.
Tested with Python 3.14.4, Matplotlib 3.10.7, NumPy 2.3.5.
Run from _media with MPLBACKEND=Agg and MPLCONFIGDIR in /tmp.
The matching PNG basename is written to the current working directory.
"""
from pathlib import Path
import matplotlib.pyplot as plt
ADDRESSES = (0, 4, 32, 0, 16, 32, 4, 48, 52, 0, 16, 0)
BLOCK_BYTES = 16
CAPACITY = 2
def enumerate_trace():
"""Keep physical slots fixed; keep recency separately, oldest first."""
slots = [None] * CAPACITY
recency = []
seen = set()
rows = []
for step, address in enumerate(ADDRESSES, 1):
line = address // BLOCK_BYTES
hit = line in recency
victim = None
if hit:
recency.remove(line)
else:
if len(recency) == CAPACITY:
victim = recency.pop(0)
slot = slots.index(victim)
else:
slot = slots.index(None)
slots[slot] = line
recency.append(line)
outcome = "H" if hit else ("M cold" if line not in seen else "M capacity")
rows.append((step, address, line, outcome, victim, tuple(slots), tuple(recency)))
seen.add(line)
return rows
def main():
rows = enumerate_trace()
assert sum(row[3] == "H" for row in rows) == 5
assert rows[3][6] == (2, 0) and rows[4][4] == 2
plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 11})
fig, ax = plt.subplots(figsize=(10.4, 6.4), dpi=120)
fig.patch.set_facecolor("white")
ax.axis("off")
fig.suptitle("Fully associative LRU: identity, slots, and recency", fontsize=17,
fontweight="bold", y=0.96)
fig.text(0.5, 0.905, "Synthetic byte reads • 16 bytes / line • 2 resident slots • initially empty",
ha="center", fontsize=11)
labels = ["Read", "Address", "Line q", "Outcome", "Evict q", "Slot 0", "Slot 1", "LRU → MRU"]
def entry(value):
return "—" if value is None else str(value)
cells = [[str(i), str(a), str(q), outcome, entry(victim), entry(slots[0]),
entry(slots[1]), " → ".join(map(str, order))]
for i, a, q, outcome, victim, slots, order in rows]
table = ax.table(cellText=cells, colLabels=labels, cellLoc="center", loc="center",
colWidths=[0.065, 0.09, 0.09, 0.16, 0.105, 0.1, 0.1, 0.18],
bbox=[0, 0, 1, 1])
table.auto_set_font_size(False)
table.set_fontsize(11)
for (r, c), cell in table.get_celld().items():
cell.set_edgecolor("#ccd4df")
cell.set_linewidth(0.6)
if r == 0:
cell.set_facecolor("#e5edf7")
cell.set_text_props(weight="bold", color="#18354f")
else:
cell.set_facecolor("white" if r % 2 else "#f5f7fa")
if c == 3:
cell.set_facecolor("#d9eee5" if rows[r - 1][3] == "H" else "#f8e5dd")
if r in (4, 5) and c in (4, 7):
cell.set_text_props(weight="bold")
fig.text(0.5, 0.095, "5 hits • 7 misses = 4 cold + 3 capacity\n"
"Read 4 refreshes line 0; read 5 therefore evicts line 2. Slots do not move on hits.",
ha="center", fontsize=11, linespacing=1.6)
fig.text(0.5, 0.035, "No prefetching, writes, invalidations, or overlapping requests. H = hit; M = miss.",
ha="center", fontsize=10)
fig.subplots_adjust(left=0.045, right=0.955, top=0.855, bottom=0.19)
fig.savefig(Path(__file__).stem + ".png", facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()