Skip to content

Commit b7da545

Browse files
committed
Paper: Caching for fast notebook restarts
1 parent 1b25bdd commit b7da545

16 files changed

Lines changed: 2430 additions & 0 deletions
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Generated vector figures. `save_fig` writes both .svg and .png; we
2+
# track only the .png (vector XML dumps thousands of noisy diff lines).
3+
# Regenerate locally with `make figures`.
4+
*.svg
554 KB
Loading
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Standalone render of the key-derivation listing, rasterized to PNG
2+
// and composed into figs/fig1_dispatch.png (see compose_fig1.py).
3+
// Mirrors the styling the paper previously applied via @preview/algo.
4+
#import "@preview/algo:0.3.6": code
5+
6+
#set page(width: auto, height: auto, margin: 2pt, fill: none)
7+
8+
#code(
9+
fill: rgb(99%, 99%, 99%),
10+
stroke: 0.6pt + rgb(70%, 70%, 70%),
11+
radius: 2pt,
12+
inset: 7pt,
13+
row-gutter: 6.5pt,
14+
main-text-styles: (size: 8.5pt),
15+
line-number-styles: (size: 7.5pt, fill: rgb(45%, 45%, 45%)),
16+
)[#raw(lang: "py", block: false, "def derive_key(cell, graph, scope) -> HashKey:\n refs = ScopedVisitor(cell.module).refs # static analysis\n refs = normalize_scope(refs, scope) # UI/state -> values\n h, kind = sha256(), \"Pure\" # no refs: pure cell\n\n if refs: # content-address first\n kind = \"ContentAddressed\"\n refs, serial = content_serialize(refs, scope)\n for ref in sorted(serial):\n h.update(serial[ref]) # buffer-protocol view\n\n if refs: # substitute producers\n kind = \"ExecutionPath\"\n for parent in producing_cells(refs, graph):\n h.update(derive_key(parent, graph, scope).digest)\n\n if refs - scoped_refs: # same-cell context\n kind = \"ContextExecutionPath\"\n h.update(hash_module(cell.context))\n\n h.update(hash_module(compile(cell.module))) # bytecode, not source\n return HashKey(h.digest(), kind)")]
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# /// script
2+
# requires-python = ">=3.11"
3+
# dependencies = ["pillow"]
4+
# ///
5+
"""Compose Figure 1: top-down dispatch flow (left) beside the
6+
rasterized key-derivation listing (right).
7+
8+
Inputs (both rendered at 300 ppi):
9+
fig1_dispatch_flow.png — `dot -Tpng -Gdpi=300 fig1_dispatch.dot`
10+
alg_hash.png — `typst compile --format png --ppi 300 alg_hash.typ`
11+
12+
Output: fig1_dispatch.png, transparent background, panels scaled to a
13+
common height with a small gutter.
14+
"""
15+
16+
from PIL import Image
17+
18+
GUTTER = 90 # px at 300 ppi ≈ 7.6 mm
19+
20+
flow = Image.open("fig1_dispatch_flow.png").convert("RGBA")
21+
alg = Image.open("alg_hash.png").convert("RGBA")
22+
23+
# Scale the listing to the flow's height (flow sets the height budget).
24+
h = flow.height
25+
alg = alg.resize((round(alg.width * h / alg.height), h), Image.LANCZOS)
26+
27+
canvas = Image.new("RGBA", (flow.width + GUTTER + alg.width, h), (0, 0, 0, 0))
28+
canvas.paste(flow, (0, 0), flow)
29+
canvas.paste(alg, (flow.width + GUTTER, 0), alg)
30+
canvas.save("fig1_dispatch.png")
31+
print(f"fig1_dispatch.png: {canvas.width}x{canvas.height}")
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Cache key dispatch — flat three-way fallback, top-down flow.
2+
// Rendered to figs/fig1_dispatch_flow.png via `make flowchart`, then
3+
// composed with the rasterized derivation listing (figs/alg_hash.typ)
4+
// into figs/fig1_dispatch.png by figs/compose_fig1.py.
5+
//
6+
// A per-ref dispatch tries three categories in order:
7+
// 1. Pure — immutable primitives, hash the value directly.
8+
// 2. ContentAddressed — buffer-protocol bytes, hash the buffer.
9+
// 3. ExecutionPath — fall back to the producing cell's stored H.
10+
// All three feed the same sha256 combiner at the bottom, which
11+
// concatenates the per-ref keys with the cell's compiled bytecode to
12+
// produce H(cell).
13+
14+
digraph dispatch {
15+
rankdir = TB;
16+
graph [bgcolor="transparent", fontname="serif", fontsize=11,
17+
nodesep=0.25, ranksep=0.32];
18+
node [fontname="serif", fontsize=10, color="#333333", penwidth=0.9,
19+
margin="0.10,0.05"];
20+
edge [fontname="serif", fontsize=9, color="#555555", arrowsize=0.7];
21+
22+
// ── entry ─────────────────────────────────────────────────────
23+
ref [label="per ref",
24+
shape=box, style="rounded,filled", fillcolor="#f5f5f5"];
25+
26+
// ── decisions ────────────────────────────────────────────────
27+
q_pure [label="immutable?",
28+
shape=diamond, style=filled, fillcolor="#e3f2fd"];
29+
q_buf [label="buffer\nprotocol?",
30+
shape=diamond, style=filled, fillcolor="#e8f5e9"];
31+
32+
// ── three terminal categories ────────────────────────────────
33+
pure [label="Pure\nsha256(value)",
34+
shape=box, style="rounded,filled", fillcolor="#e3f2fd"];
35+
ca [label="ContentAddressed\nsha256(buffer)",
36+
shape=box, style="rounded,filled", fillcolor="#e8f5e9"];
37+
ep [label="ExecutionPath\nH(parent)",
38+
shape=box, style="rounded,filled", fillcolor="#fff3e0"];
39+
40+
// ── combiner + output (bottom) ───────────────────────────────
41+
src [label="cell bytecode\nsha256(bytecode)",
42+
shape=box, style="rounded,filled", fillcolor="#f5f5f5"];
43+
combine [label="combine keys\nsha256(src ‖ k₁ ‖ k₂ ‖ …)",
44+
shape=box, style="rounded,filled", fillcolor="#fafafa"];
45+
out [label="H(cell)",
46+
shape=oval, style=filled, fillcolor="#fff9c4"];
47+
48+
// ── flow ────────────────────────────────────────────────────
49+
ref -> q_pure;
50+
q_pure -> pure [label="yes"];
51+
q_pure -> q_buf [label="no"];
52+
q_buf -> ca [label="yes"];
53+
q_buf -> ep [label="no"];
54+
55+
pure -> combine;
56+
ca -> combine;
57+
ep -> combine;
58+
src -> combine;
59+
combine -> out;
60+
61+
// decisions on the spine, terminals beside them
62+
{ rank=same; q_pure; pure; }
63+
{ rank=same; q_buf -> ca -> ep [style=invis]; }
64+
{ rank=same; src; combine; }
65+
}
719 KB
Loading
181 KB
Loading
84.3 KB
Loading
146 KB
Loading
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"""Library code for the paper notebook.
2+
3+
Exposes two names to the figure cells in main.md:
4+
5+
- ``compute``: benchmark primitives, plotting helpers, and the
6+
``claim(condition, label, **values)`` assertion helper.
7+
- ``save_fig``: writes a matplotlib figure to ``figs/<name>.{svg,png}``.
8+
"""
9+
from . import compute
10+
from .plotting import save_fig
11+
12+
__all__ = ["compute", "save_fig"]

0 commit comments

Comments
 (0)