codextlb-miss-versus-page-fault.py
tlb-miss-versus-page-fault.py
"""Separate TLB refill from page faults; Python 3.14 / matplotlib 3.10.7.
Run from _media; the PNG is written in the current working directory.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch, FancyBboxPatch, Polygon
INK = "#203040"
BLUE = "#155d8a"
GREEN = "#186a52"
RED = "#a43432"
def main():
plt.rcParams.update({"font.size": 12, "font.family": "DejaVu Sans"})
fig, ax = plt.subplots(figsize=(11.2, 8.9), dpi=110)
fig.patch.set_facecolor("white")
ax.set(xlim=(0, 12), ylim=(0, 10))
ax.axis("off")
def label(x, y, text, **kwargs):
color = kwargs.pop("color", INK)
ax.text(x, y, text, ha="center", va="center", color=color, **kwargs)
def box(x, y, w, h, text, color=BLUE, fill="#f0f5f9"):
ax.add_patch(FancyBboxPatch((x - w / 2, y - h / 2), w, h,
boxstyle="round,pad=0.035,rounding_size=0.08",
linewidth=1.5, edgecolor=color, facecolor=fill))
label(x, y, text, fontsize=11.5)
def diamond(x, y, w, h, text):
ax.add_patch(Polygon([(x, y + h / 2), (x + w / 2, y),
(x, y - h / 2), (x - w / 2, y)],
edgecolor=BLUE, facecolor="#e6eff7", linewidth=1.5))
label(x, y, text, fontsize=11)
def path(points, color=BLUE):
for p, q in zip(points[:-2], points[1:-1]):
ax.plot([p[0], q[0]], [p[1], q[1]], color=color, linewidth=1.5)
ax.add_patch(FancyArrowPatch(points[-2], points[-1], arrowstyle="-|>",
mutation_scale=15, color=color, linewidth=1.5))
label(6, 9.58, "A TLB miss is not necessarily a page fault", fontsize=19, weight="bold")
label(6, 9.13, "Simplified x86 hardware-walk model • ordinary paging • current address space", fontsize=11.5)
box(6, 8.52, 4.9, 0.63, "Virtual address + read / write / execute request")
diamond(6, 7.43, 3.1, 1.08, "Matching valid\nTLB entry?")
path([(6, 8.16), (6, 8.0)])
# Left: a cached translation still requires a permission check.
path([(4.4, 7.43), (2.15, 7.43), (2.15, 6.67)])
label(3.05, 7.71, "HIT", color=GREEN, weight="bold")
diamond(2.15, 6.06, 3.2, 1.15, "Cached permissions\nallow this access?")
box(2.15, 4.31, 3.36, 0.95, "Use PFN + unchanged offset\nAccess physical address", GREEN, "#e8f4ee")
path([(2.15, 5.45), (2.15, 4.83)], GREEN)
label(2.5, 5.12, "yes", color=GREEN)
box(6.0, 4.31, 3.05, 0.95, "PAGE FAULT\nDenied / not present / other", RED, "#fff0ed")
path([(3.8, 6.06), (6.0, 6.06), (6.0, 4.83)], RED)
label(4.32, 6.31, "no", color=RED)
# Right: an uncached translation may already be resident and permitted.
path([(7.6, 7.43), (9.7, 7.43), (9.7, 6.93)])
label(8.97, 7.71, "MISS", color=BLUE, weight="bold")
box(9.7, 6.56, 3.35, 0.64, "Walk page table in hardware")
path([(9.7, 6.2), (9.7, 5.95)])
diamond(9.7, 5.29, 3.65, 1.22, "Present mapping +\npermission for\nthis access?")
path([(9.7, 4.64), (9.7, 3.95)], GREEN)
label(10.08, 4.31, "yes", color=GREEN)
box(9.7, 3.39, 3.35, 1.0, "Refill TLB, then access\nResident page stays resident\nNO page fault", GREEN, "#e8f4ee")
path([(7.83, 5.29), (7.42, 5.29), (7.42, 4.88)], RED)
label(7.55, 5.6, "no", color=RED)
# Both fault paths reach OS policy; a TLB hit can fail only its access check here.
path([(6, 3.78), (6, 2.78)], RED)
box(6, 2.27, 6.65, 0.9,
"OS checks the reason and mapping policy\n"
"Supply a page / private copy, update mappings, retry; or reject",
RED, "#fff0ed")
box(6, 1.21, 10.7, 0.97,
"A page fault need not read secondary storage (for example, demand zeroing or copy-on-write).\n"
"A cached translation is not the page's contents; TLB eviction does not evict the resident page.",
BLUE, "#f7f9fb")
label(6, 0.32, "Some architectures refill the TLB in software; the refill event alone is not a nonresident page fault.", fontsize=10.5)
fig.subplots_adjust(left=0.02, right=0.98, bottom=0.02, top=0.98)
fig.savefig(Path.cwd() / "tlb-miss-versus-page-fault.png", facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()