.nornir/assets/ragnar-batch-pipeline.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1180 620" font-family="'DejaVu Sans', 'Segoe UI', sans-serif">
<defs>
<linearGradient id="board" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#0b1c2e"/>
<stop offset="1" stop-color="#06111d"/>
</linearGradient>
<linearGradient id="rail" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#173d57"/>
<stop offset="1" stop-color="#0c2438"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="1180" height="620" fill="url(#board)"/>
<g stroke="#143a52" stroke-width="1">
<line x1="0" y1="76" x2="1180" y2="76"/>
<line x1="0" y1="572" x2="1180" y2="572"/>
</g>
<!-- title -->
<text x="40" y="42" fill="#eaf6ff" font-size="22" font-weight="700">The shared batch-prefetch pipeline (MLP)</text>
<text x="470" y="42" fill="#9fc9e0" font-size="14">one driver hides the miss latency for <tspan fill="#bfe6ff" font-weight="700">both</tspan> static structures</text>
<!-- legend -->
<g font-size="12.5">
<rect x="812" y="30" width="16" height="12" rx="2" fill="#6fd3f5"/>
<text x="834" y="41" fill="#cfe6f5">SIMD compute (hot in L1)</text>
<rect x="1000" y="30" width="16" height="12" rx="2" fill="#0f2c40" stroke="#7fb0cc" stroke-dasharray="4 3"/>
<text x="1022" y="41" fill="#cfe6f5">memory wait</text>
</g>
<!-- ============ TOP: serial (stalls) ============ -->
<text x="40" y="118" fill="#eaf6ff" font-size="15" font-weight="700">serial — one query at a time</text>
<text x="330" y="118" fill="#86b3cc" font-size="12" font-family="'DejaVu Sans Mono', monospace">find_exact(q) / search(q)</text>
<text x="40" y="138" fill="#86b3cc" font-size="11.5">each hop's cache miss is a bubble the core sits idle through — latency-bound</text>
<!-- serial timeline: tiny compute then long dashed wait, repeated -->
<g>
<!-- q0 -->
<rect x="40" y="152" width="26" height="26" rx="3" fill="#6fd3f5"/>
<rect x="66" y="152" width="150" height="26" rx="3" fill="#0f2c40" stroke="#7fb0cc" stroke-width="1.4" stroke-dasharray="5 4"/>
<rect x="216" y="152" width="26" height="26" rx="3" fill="#6fd3f5"/>
<rect x="242" y="152" width="150" height="26" rx="3" fill="#0f2c40" stroke="#7fb0cc" stroke-width="1.4" stroke-dasharray="5 4"/>
<rect x="392" y="152" width="26" height="26" rx="3" fill="#6fd3f5"/>
<rect x="418" y="152" width="150" height="26" rx="3" fill="#0f2c40" stroke="#7fb0cc" stroke-width="1.4" stroke-dasharray="5 4"/>
<rect x="568" y="152" width="26" height="26" rx="3" fill="#6fd3f5"/>
<rect x="594" y="152" width="150" height="26" rx="3" fill="#0f2c40" stroke="#7fb0cc" stroke-width="1.4" stroke-dasharray="5 4"/>
<rect x="744" y="152" width="26" height="26" rx="3" fill="#6fd3f5"/>
<rect x="770" y="152" width="150" height="26" rx="3" fill="#0f2c40" stroke="#7fb0cc" stroke-width="1.4" stroke-dasharray="5 4"/>
<rect x="920" y="152" width="26" height="26" rx="3" fill="#6fd3f5"/>
<rect x="946" y="152" width="150" height="26" rx="3" fill="#0f2c40" stroke="#7fb0cc" stroke-width="1.4" stroke-dasharray="5 4"/>
</g>
<text x="40" y="200" fill="#7fa8c4" font-size="10.5" font-family="'DejaVu Sans Mono', monospace">|compute| ——— miss ——— |compute| ——— miss ——— ≈ 6× the wall-clock for the same work</text>
<!-- ============ BOTTOM: pipelined (P in flight) ============ -->
<text x="40" y="256" fill="#eaf6ff" font-size="15" font-weight="700">pipelined — P queries in flight</text>
<text x="330" y="256" fill="#86b3cc" font-size="12" font-family="'DejaVu Sans Mono', monospace">batch_stream::<P> / search_batch</text>
<text x="40" y="276" fill="#86b3cc" font-size="11.5">each query prefetches its next hop, then yields; another query's compute fills the gap — throughput-bound</text>
<!-- P lanes, staggered, computes packed with prefetch arrows -->
<g font-family="'DejaVu Sans Mono', monospace" font-size="10.5">
<text x="16" y="304" fill="#9fc9e0">q0</text>
<text x="16" y="330" fill="#9fc9e0">q1</text>
<text x="16" y="356" fill="#9fc9e0">q2</text>
<text x="16" y="382" fill="#9fc9e0">q3</text>
<text x="16" y="408" fill="#9fc9e0">⋮</text>
</g>
<!-- lane q0 -->
<g>
<rect x="40" y="292" width="26" height="20" rx="3" fill="#6fd3f5"/>
<rect x="200" y="292" width="26" height="20" rx="3" fill="#6fd3f5"/>
<rect x="360" y="292" width="26" height="20" rx="3" fill="#6fd3f5"/>
<path d="M66 302 H200" stroke="#7fb0cc" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/>
<path d="M226 302 H360" stroke="#7fb0cc" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/>
</g>
<!-- lane q1 (staggered) -->
<g>
<rect x="80" y="318" width="26" height="20" rx="3" fill="#6fd3f5"/>
<rect x="240" y="318" width="26" height="20" rx="3" fill="#6fd3f5"/>
<rect x="400" y="318" width="26" height="20" rx="3" fill="#6fd3f5"/>
<path d="M106 328 H240" stroke="#7fb0cc" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/>
<path d="M266 328 H400" stroke="#7fb0cc" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/>
</g>
<!-- lane q2 -->
<g>
<rect x="120" y="344" width="26" height="20" rx="3" fill="#6fd3f5"/>
<rect x="280" y="344" width="26" height="20" rx="3" fill="#6fd3f5"/>
<rect x="440" y="344" width="26" height="20" rx="3" fill="#6fd3f5"/>
<path d="M146 354 H280" stroke="#7fb0cc" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/>
<path d="M306 354 H440" stroke="#7fb0cc" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/>
</g>
<!-- lane q3 -->
<g>
<rect x="160" y="370" width="26" height="20" rx="3" fill="#6fd3f5"/>
<rect x="320" y="370" width="26" height="20" rx="3" fill="#6fd3f5"/>
<rect x="480" y="370" width="26" height="20" rx="3" fill="#6fd3f5"/>
<path d="M186 380 H320" stroke="#7fb0cc" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/>
<path d="M346 380 H480" stroke="#7fb0cc" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/>
</g>
<!-- packed compute band highlight -->
<rect x="36" y="288" width="480" height="108" rx="8" fill="none" stroke="#3f7597" stroke-width="1.3" stroke-dasharray="3 4"/>
<text x="524" y="330" fill="#bfe6ff" font-size="12" font-weight="700">core stays busy</text>
<text x="524" y="348" fill="#86b3cc" font-size="10.5">misses overlap across the P lanes</text>
<text x="524" y="366" fill="#86b3cc" font-size="10.5">P=16 pegs every core at 100%</text>
<!-- ============ SHARED DRIVER RAIL ============ -->
<rect x="40" y="432" width="1100" height="112" rx="12" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2"/>
<text x="60" y="460" fill="#dff1ff" font-size="15" font-weight="700">one driver, two payloads</text>
<text x="256" y="460" fill="#9fc9e0" font-size="12">the const-P prefetch pipeline is the reusable primitive; only the per-hop compute differs</text>
<g>
<rect x="60" y="474" width="520" height="54" rx="8" fill="#0f2c40" stroke="#4f8aab" stroke-width="1.5"/>
<text x="320" y="495" fill="#eaf6ff" font-size="12.5" text-anchor="middle" font-weight="700">stree32 hop</text>
<text x="320" y="514" fill="#9fc9e0" font-size="10.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">prefetch child node → count_lt → descend one level</text>
<rect x="600" y="474" width="540" height="54" rx="8" fill="#0f2c40" stroke="#4f8aab" stroke-width="1.5"/>
<text x="870" y="495" fill="#eaf6ff" font-size="12.5" text-anchor="middle" font-weight="700">vann / RagnarsEmb hop</text>
<text x="870" y="514" fill="#9fc9e0" font-size="10.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">prefetch next posting rows → score_i8_batch → merge top-k</text>
</g>
</svg>