Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions SESSION-LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ Every performance figure quoted below is reproducible with `./verify.sh` (see
[README.md](README.md)); timings depend on hardware, everything else is seeded.

<!-- newest first: date — what was done -->
## 2026-08-04 — topic 00 — reading-drepper: Steps 5–6 rewritten, plus a concept→profiler map

**Reader feedback on [`reading-drepper.md`](topics/00-performance-toolbox/reading-drepper.md): Step 5 unclear, Step 6's diagram under-explained, and a general question — how do you identify these eight concepts in a program you did not write?** No new measurements; every number below already existed in [topic 0's notes.md](topics/00-performance-toolbox/notes.md) and is now cross-referenced from the concept that explains it.

**Step 5 (dependent loads) rebuilt around one claim: the cost of a miss is not a property of the miss.** It opens with what "dependent" means at the instruction level (`chain[idx]`, `node->next->next`, a B-tree child pointer inside the parent you are still waiting for), then an ASCII timeline contrasting three overlapping misses (~105 ns total, ~35 ns apiece) with three serialized ones (~300 ns, 100 ns apiece), then the point people skip: **latency-bound and bandwidth-bound are opposites.** A chase moves one 128-byte line per ~104 ns ≈ **1.2 GB/s** against the **24–57 GB/s** a single core reaches on topic 12's streaming scan — slow while the bus idles, so no layout fix touches it. The payoff is a two-row table putting this repo's own numbers on both sides of the diagram: `lookup_shootout` `hashmap` at n=1e7, ~160 MB, 1024 **independent** probes → **9.3 ns**; `cache_ladder` at 128 MB, a **dependent** chase → **104 ns**. Same DRAM, same misses, **11×** apart on overlap alone — which is the real explanation for why the hash table looked suspiciously flat at ten million keys. Then the three construction choices of `cache_ladder` are each justified separately (the dependency lives in the *data* so no compiler or core can speculate around it; Sattolo's *cyclic* permutation both defeats the prefetcher and stops a short sub-cycle living in L1; the cursor carried across criterion iterations — with the original benchmark's ~25 ns "DRAM" reading cited as the failure it prevents), and the readout stated plainly: with no arithmetic between loads, `elapsed / steps` *is* one access's latency.

**Step 6 (virtual memory) gained the five things the diagram assumed.** Why a tree at all — a flat table for a 47-bit space at 16 KB pages is 2³³ × 8 B = **64 GB per process**, so the radix tree is what buys sparsity, and depth is the price. A bit-field diagram of one x86-64 address (9/9/9/9 + 12-bit offset) showing *why* 9 bits — one table is one 4 KB page = 512 entries — with each arrow annotated as a real load whose address comes from the entry just fetched: **Step 5's chain, in silicon, before your access can issue.** A three-column naming table (PML4/PDPT/PD/PT = PGD/PUD/PMD/PTE = L0–L3) since all three appear in the sources. The Apple Silicon variant derived rather than asserted: a 16 KB granule means 2048-entry tables = 11-bit indices, and `14 + 11 + 11 + 11 = 47`, so the walk is **three levels, not four** — bigger pages buy a shorter walk *and* 4× the reach. And four reasons it isn't catastrophic: hardware walks it (a page *fault* is the kernel, microseconds, a different event), the tables are ordinary cacheable memory, page-walk caches hold partial translations, and huge pages turn an L2/PMD entry into a block descriptor covering 2 MB (32 MB at a 16 KB granule). Closed against the measurement: `cache_ladder`'s tail **87 → 113 ns** from 64 MB to 512 MB is **+26 ns** of walk once 32K pages overflow the TLB — not the +400 ns of a fully cold walk, not zero. "That +26 ns is this diagram, priced."

**New section: "Finding these concepts in a real program"** — the general question, answered as a method. Three instruments in reach-for order, with the trap stated first: a sampling profiler attributes stall time to the *waiting* instruction, so memory-bound and compute-bound loops look identical, and this repo has the artifact to prove it (the `lookup_shootout` flamegraph's 21% SipHash / ~79% inlined probe loop, which no amount of staring could split). Counters name the wall (`perf stat` on Linux; Instruments → CPU Counters on macOS, which has no `perf`; a Linux VM for `perf c2c`). A **differential experiment** — change one thing, re-measure — is the only portable instrument and the one this repo leans on, because a counter says a number is high while a differential proves fixing it would help. A mermaid funnel routes from IPC + branch-miss rate + achieved GB/s + dTLB misses to one of five verdicts (compute / branch / bandwidth / translation / latency-bound), with the last split — same flamegraph, opposite fixes — as its point. Then an eight-row table: concept → signature in a profile → Linux counter → **the differential that proves it**. The sharp ones: pad a stride by one line to separate conflict from capacity; feed the same loop sorted vs shuffled indices to price the prefetcher; run *k* interleaved cursors and watch per-step time fall ~k× to prove spare MLP (which is what batched lookup APIs collect); `perf c2c` plus a 128-byte pad to confirm false sharing. Closes on two habits — always pair a counter with a differential, and compute useful-bytes ÷ bytes-moved by hand, since that ratio needs no profiler and decides row-vs-column in topic 12.

Also: a fourth `notes.md` question (make `lookup_shootout`'s 1e7 probes dependent and report the new ns/probe — prove the MLP claim with the differential rather than by reasoning), two new `Done when` items (state the latency/bandwidth distinction and the one measurement that separates them; name counter *and* differential for all eight concepts), and a Tools block in the references. Verified: `mdbook build` clean, the new flowchart renders to a real SVG under headless Chrome with no syntax error, and every relative link on the rendered page resolves — including `experiments/benches/cache_ladder.rs`, which mdbook copies verbatim.

## 2026-07-28 — repo-wide audit: verify.sh coverage, CI, and the conventions backfilled

**Repo-wide review and fix pass — no new topics, but the measurement spine rebuilt.** Prompted by a full audit of all 44 packages, 230 reading guides, 45 crates and the book build. What the audit found and what was done:
Expand Down
Loading