Unverified Commit 222c2e85 authored by dagil-nvidia's avatar dagil-nvidia Committed by GitHub
Browse files

docs: add Flash Indexer blog post (#6472)


Signed-off-by: default avatarDan Gil <dagil@nvidia.com>
Signed-off-by: default avatardagil-nvidia <dagil@nvidia.com>
Co-authored-by: default avatarCursor <cursoragent@cursor.com>
parent d1bd210f
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Generate the KV event density heatmap (Figure 1) for the Flash Indexer blog post.
Renders a diverging heatmap showing Store vs Remove event density across
16 workers over time. Uses real Mooncake FAST'25 trace data when available,
otherwise falls back to synthetic Gamma/Zipf event patterns.
Prerequisites:
pip3 install plotly kaleido numpy pyyaml
Usage:
python3 gen_heatmap.py # synthetic data
python3 gen_heatmap.py --real-data PATH # real Mooncake trace
"""
from __future__ import annotations
import argparse
import gzip
import json
import sys
from pathlib import Path
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
sys.path.insert(0, str(Path(__file__).parent))
from plotly_dynamo import dynamo_template, load_tokens
TOKENS = load_tokens()
C = TOKENS["colors"]
T = TOKENS["typography"]
BG = C["background"]["primary"]
SURFACE = C["background"]["surface"]
BORDER = C["border"]["subtle"]
TXT = C["text"]["primary"]
TXT2 = C["text"]["secondary"]
STORE = "#76b900"
REMOVE = "#fac200"
SANS = T["font_family"]
MONO = T["font_family_mono"]
OUT = Path(__file__).resolve().parent.parent / "images"
def generate_kv_events(
num_workers: int = 16,
duration_ms: float = 100.0,
rps_per_worker: float = 35.0,
block_size: int = 16,
cache_hit_ratio: float = 0.30,
cache_capacity_blocks: int = 24,
seed: int = 42,
) -> tuple[list[np.ndarray], list[np.ndarray]]:
"""Synthetic KV Store/Remove events.
Arrivals: Gamma(alpha=1.5) -- bursty.
Prompt lengths: Zipf(a=1.3) * 384 + 64 -- heavy-tailed.
Low cache capacity forces frequent eviction sweeps.
"""
rng = np.random.default_rng(seed)
gamma_alpha = 1.5
all_stores: list[np.ndarray] = []
all_removes: list[np.ndarray] = []
for _ in range(num_workers):
mean_iat_ms = 1000.0 / rps_per_worker
gamma_beta = gamma_alpha / mean_iat_ms
stores, removes = [], []
t = rng.exponential(mean_iat_ms / 3)
occupied = 0
while t < duration_ms:
prompt_tokens = int(rng.zipf(1.3) * 384 + 64)
prompt_tokens = min(prompt_tokens, 8192)
total_blocks = max(1, prompt_tokens // block_size)
new_blocks = max(1, int(total_blocks * (1 - cache_hit_ratio)))
if occupied > cache_capacity_blocks:
evict_n = occupied - int(cache_capacity_blocks * 0.6)
evict_n = max(4, evict_n)
evict_t = t + rng.uniform(0, 0.06)
removes.extend(evict_t + rng.uniform(0, 0.06, size=evict_n))
occupied -= evict_n
store_t = t + rng.uniform(0.12, 0.25)
stores.extend(store_t + rng.uniform(0, 0.08, size=new_blocks))
occupied += new_blocks
t += rng.gamma(gamma_alpha, 1.0 / gamma_beta)
all_stores.append(np.sort(stores))
all_removes.append(np.sort(removes))
return all_stores, all_removes
def save(fig: go.Figure, name: str, w: int = 1200, h: int = 600) -> None:
"""Write figure as both PNG (3x) and SVG."""
OUT.mkdir(parents=True, exist_ok=True)
png = OUT / f"{name}.png"
svg = OUT / f"{name}.svg"
fig.write_image(str(png), width=w, height=h, scale=3)
fig.write_image(str(svg), width=w, height=h)
print(f" {png.name} ({w}x{h})")
print(f" {svg.name} ({w}x{h})")
def _ax(**kw) -> dict:
"""Clean axis defaults with minimal grid."""
base = {
"zeroline": False,
"showgrid": True,
"gridcolor": BORDER,
"gridwidth": 0.3,
"linecolor": BORDER,
"linewidth": 0.5,
"tickfont": {"family": SANS, "size": 12, "color": TXT2},
"title_font": {"family": SANS, "size": 14, "color": TXT2},
}
base.update(kw)
return base
def load_real_events(
path: Path,
t_start_s: float = 5.0,
t_end_s: float = 10.0,
) -> tuple[int, np.ndarray, np.ndarray, np.ndarray, float, int, int]:
"""Load real KV events from JSON, return binned matrices for the time window.
Returns (num_workers, s_mat, r_mat, bins, bin_width, total_stores, total_removes).
Times are converted to ms relative to t_start.
"""
p = Path(path)
opener = gzip.open if p.suffix == ".gz" else p.open
with opener(p, "rt") as f:
data = json.load(f)
t_start_us = t_start_s * 1e6
t_end_us = t_end_s * 1e6
duration_ms = (t_end_s - t_start_s) * 1000
worker_ids = sorted(int(k) for k in data)
n = len(worker_ids)
bw = 10.0
bins = np.arange(0, duration_ms + bw, bw)
nb = len(bins) - 1
s_mat = np.zeros((n, nb))
r_mat = np.zeros((n, nb))
total_stores = 0
total_removes = 0
for idx, wid in enumerate(worker_ids):
events = data[str(wid)]
for ev in events:
ts_us = ev["timestamp_us"]
if ts_us < t_start_us or ts_us > t_end_us:
continue
ts_ms = (ts_us - t_start_us) / 1000.0
bin_idx = min(int(ts_ms / bw), nb - 1)
d = ev["event"]["data"]
if "stored" in d:
s_mat[idx, bin_idx] += 1
total_stores += 1
elif "removed" in d:
r_mat[idx, bin_idx] += 1
total_removes += 1
return n, s_mat, r_mat, bins, bw, total_stores, total_removes
def make_heatmap(
stores: list[np.ndarray],
removes: list[np.ndarray],
real_data_path: Path | None = None,
) -> None:
if real_data_path is not None:
n, s_mat, r_mat, bins, bw, ts_count, tr_count = load_real_events(real_data_path)
nb = len(bins) - 1
duration_ms = bins[-1]
total_events = ts_count + tr_count
subtitle = f"Mooncake trace (5%) \u00b7 16 Mocker workers \u00b7 2048 GPU blocks/worker \u00b7 {total_events:,} events in 5.0 s"
else:
n = len(stores)
bw = 0.5
duration_ms = 100.0
bins = np.arange(0, duration_ms + bw, bw)
nb = len(bins) - 1
s_mat = np.zeros((n, nb))
r_mat = np.zeros((n, nb))
for i in range(n):
if len(stores[i]):
s_mat[i] = np.histogram(stores[i], bins)[0]
if len(removes[i]):
r_mat[i] = np.histogram(removes[i], bins)[0]
ts_count = sum(len(s) for s in stores)
tr_count = sum(len(r) for r in removes)
subtitle = f"16 workers \u00b7 TP1 \u00b7 block_size 16 \u00b7 35 RPS/worker \u00b7 30% cache hit \u00b7 {(ts_count + tr_count) // 1000}K events in 100 ms"
combined = s_mat - r_mat
total = combined.sum(axis=0)
disp_pw = np.where(s_mat >= r_mat, s_mat, -r_mat).astype(float)
disp_pw = np.where((s_mat == 0) & (r_mat == 0), 0.0, disp_pw)
s_total = s_mat.sum(axis=0)
r_total = r_mat.sum(axis=0)
disp_tot = np.where(s_total >= r_total, s_total, -r_total).astype(float)
disp_tot = np.where((s_total == 0) & (r_total == 0), 0.0, disp_tot)
pw_zmax = 10.0
colorscale = [
[0.0, REMOVE],
[0.15, "#c89a00"],
[0.5, BG],
[0.85, "#5aaa00"],
[1.0, STORE],
]
fig = make_subplots(
rows=2,
cols=1,
shared_xaxes=True,
row_heights=[0.8, 0.2],
vertical_spacing=0.05,
)
fig.update_layout(template=dynamo_template)
tick_vals = [-10, -5, 0, 5, 10]
tick_text = ["\u221210", "\u22125", "0", "5", "10"]
fig.add_trace(
go.Heatmap(
z=disp_pw,
x0=0,
dx=bw,
y0=0,
dy=1,
colorscale=colorscale,
zmid=0,
zmin=-pw_zmax,
zmax=pw_zmax,
colorbar={
"title": {"text": ""},
"tickfont": {"family": SANS, "size": 12, "color": TXT2},
"thickness": 12,
"len": 0.62,
"y": 0.62,
"x": 1.027,
"tickvals": tick_vals,
"ticktext": tick_text,
},
customdata=combined,
hovertemplate="W%{y} \u00b7 t=%{x:.0f}ms<br>net %{customdata:.0f}<extra></extra>",
xgap=0.5,
ygap=0.5,
),
row=1,
col=1,
)
tot_zmax = 100.0
tick_vals_tot = [-100, 0, 100]
tick_text_tot = ["\u2212100", "0", "100"]
fig.add_trace(
go.Heatmap(
z=[disp_tot],
x0=0,
dx=bw,
colorscale=colorscale,
zmid=0,
zmin=-tot_zmax,
zmax=tot_zmax,
colorbar={
"title": {"text": ""},
"tickfont": {"family": SANS, "size": 12, "color": TXT2},
"thickness": 12,
"len": 0.16,
"y": 0.095,
"x": 1.027,
"tickvals": tick_vals_tot,
"ticktext": tick_text_tot,
},
customdata=[total],
hovertemplate="t=%{x:.0f}ms<br>\u03a3 net %{customdata:.0f}<extra></extra>",
xgap=0.5,
showscale=True,
),
row=2,
col=1,
)
fig.update_layout(
title={"text": ""},
margin={"l": 65, "r": 120, "t": 110, "b": 55},
plot_bgcolor=BG,
paper_bgcolor=BG,
)
fig.add_annotation(
text="KV Events",
xref="paper",
yref="paper",
x=1.015,
y=0.62,
xanchor="center",
yanchor="middle",
textangle=-90,
font={"family": SANS, "size": 13, "color": TXT2},
showarrow=False,
)
fig.add_annotation(
text="KV Events",
xref="paper",
yref="paper",
x=1.015,
y=0.095,
xanchor="center",
yanchor="middle",
textangle=-90,
font={"family": SANS, "size": 13, "color": TXT2},
showarrow=False,
)
fig.add_annotation(
text="Store",
xref="paper",
yref="paper",
x=1.06,
y=0.935,
xanchor="center",
yanchor="bottom",
font={"family": SANS, "size": 13, "color": TXT2},
showarrow=False,
)
fig.add_annotation(
text="Remove",
xref="paper",
yref="paper",
x=1.06,
y=0.305,
xanchor="center",
yanchor="top",
font={"family": SANS, "size": 13, "color": TXT2},
showarrow=False,
)
fig.add_annotation(
text="Store",
xref="paper",
yref="paper",
x=1.06,
y=0.18,
xanchor="center",
yanchor="bottom",
font={"family": SANS, "size": 13, "color": TXT2},
showarrow=False,
)
fig.add_annotation(
text="Remove",
xref="paper",
yref="paper",
x=1.06,
y=0.005,
xanchor="center",
yanchor="top",
font={"family": SANS, "size": 13, "color": TXT2},
showarrow=False,
)
fig.add_annotation(
text="KV CACHE EVENT DENSITY",
xref="paper",
yref="paper",
x=0.0,
y=1.16,
xanchor="left",
yanchor="bottom",
font={"family": SANS, "size": 18, "color": TXT},
showarrow=False,
)
fig.add_annotation(
text=subtitle,
xref="paper",
yref="paper",
x=0.0,
y=1.09,
xanchor="left",
yanchor="bottom",
font={"family": SANS, "size": 12, "color": TXT2},
showarrow=False,
)
fig.add_annotation(
text=(
f"<span style='color:{STORE}'>\u25a0</span> Store (prefill) "
f"<span style='color:{REMOVE}'>\u25a0</span> Remove (eviction)"
),
xref="paper",
yref="paper",
x=1.0131,
y=1.09,
xanchor="right",
yanchor="bottom",
font={"family": SANS, "size": 13, "color": TXT2},
showarrow=False,
)
fig.update_xaxes(row=1, col=1, **_ax(range=[0, duration_ms]))
fig.update_xaxes(row=2, col=1, **_ax(title="Time (ms)", range=[0, duration_ms]))
fig.update_yaxes(
row=1,
col=1,
**_ax(title="Worker", tickvals=list(range(0, 16, 5)) + [15], showgrid=False),
)
fig.update_yaxes(
row=2,
col=1,
**_ax(
title="\u03a3 Workers",
showgrid=False,
tickvals=[],
showticklabels=False,
showline=True,
linecolor=BORDER,
linewidth=0.5,
),
)
save(fig, "fig-1-kv-event-density", w=950, h=580)
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--real-data",
type=Path,
default=None,
help="Path to kv_events JSON or .json.gz (Mooncake trace). Uses synthetic data if omitted.",
)
args = parser.parse_args()
print("Generating synthetic KV events (Gamma arrivals \u00d7 Zipf bursts)...")
stores, removes = generate_kv_events()
ts = sum(len(s) for s in stores)
tr = sum(len(r) for r in removes)
print(f" {ts:,} Store events, {tr:,} Remove events over 100ms\n")
print("Rendering heatmap...")
if args.real_data and args.real_data.exists():
print(f" (using real event data from {args.real_data})")
make_heatmap(stores, removes, real_data_path=args.real_data)
else:
if args.real_data:
print(f" WARNING: {args.real_data} not found, using synthetic data")
make_heatmap(stores, removes)
print(f"\nDone \u2192 {OUT}")
if __name__ == "__main__":
main()
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Plot achieved vs. offered throughput from mooncake_bench sweep data.
Uses the Dynamo dark Plotly template (design_tokens.yaml + plotly_dynamo.py).
Usage:
python3 gen_throughput.py ../data/sweep_plot.json
"""
from __future__ import annotations
import argparse
import json
import math
import sys
import warnings
from pathlib import Path
import plotly.graph_objects as go
sys.path.insert(0, str(Path(__file__).parent))
from plotly_dynamo import build_template, load_tokens
BACKENDS = {
"nested-map": {
"label": "Concurrent Positional Indexer (Flash Indexer)",
"color": "#76b900", # Dynamo green -- best performer
"version": "Dynamo v1.0.0",
},
"concurrent-radix-tree": {
"label": "Concurrent Radix Tree",
"color": "#008564", # Emerald -- strong second
"version": "Dynamo v1.0.0",
},
"radix-tree": {
"label": "Radix Tree",
"color": "#fac200", # Fluorite -- middle
"version": "Dynamo v0.1.0",
},
"inverted-index": {
"label": "Inverted Index",
"color": "#969696", # Silver Gray (7.1:1 on black) -- weak
"version": "Naive",
},
"naive-nested-map": {
"label": "Naive Nested Map",
"color": "#767676", # Muted Gray (4.6:1 on black) -- worst
"version": "Naive",
},
}
PLOT_ORDER = list(BACKENDS.keys())
def main():
parser = argparse.ArgumentParser(description=__doc__)
images_dir = Path(__file__).resolve().parent.parent / "images"
default_out = str(images_dir / "fig-6-indexer-throughput.png")
parser.add_argument("json_path", help="Path to sweep_plot.json")
parser.add_argument(
"-o", "--output", default=default_out, help="Output path (.png, .svg, .pdf)"
)
parser.add_argument("--width", type=int, default=775, help="Figure width in px")
parser.add_argument("--height", type=int, default=650, help="Figure height in px")
args = parser.parse_args()
with open(args.json_path) as f:
data = json.load(f)
tokens = load_tokens(Path(__file__).parent / "design_tokens.yaml")
template = build_template(tokens)
series_colors = tokens["colors"]["chart_series"]
border_subtle = tokens["colors"]["border"]["subtle"]
ordered = [(k, data[k]) for k in PLOT_ORDER if k in data]
for k in data:
if k not in PLOT_ORDER:
ordered.append((k, data[k]))
fig = go.Figure()
axis_min = 1e5 # 100k fixed floor
x_max = 2e9 # 2.0G
y_max = 5e8 # 500M
fig.add_trace(
go.Scatter(
x=[axis_min, x_max],
y=[axis_min, x_max],
mode="lines",
line=dict(color=border_subtle, width=1, dash="dash"),
showlegend=False,
hoverinfo="skip",
)
)
for i, (name, steps) in enumerate(ordered):
meta = BACKENDS.get(name, {})
color = meta.get("color", series_colors[i % len(series_colors)])
display = meta.get("label", name.replace("-", " ").title())
offered = [s["offered_block_throughput"] for s in steps]
achieved = [s["block_throughput"] for s in steps]
fig.add_trace(
go.Scatter(
x=offered,
y=achieved,
mode="lines+markers",
name=display,
line=dict(color=color, width=2.5),
marker=dict(size=7, color=color),
hovertemplate=(
f"<b>{display}</b><br>"
"Offered: %{x:.2s} ops/s<br>"
"Achieved: %{y:.2s} ops/s"
"<extra></extra>"
),
)
)
peak_annotations = []
peak_shapes = []
peak_values = {}
label_x = 1e9 # 1.0G mark
peak_header_added = False
for name, steps in ordered:
meta = BACKENDS.get(name, {})
color = meta.get("color", "#ffffff")
version = meta.get("version", "")
best = max(steps, key=lambda s: s["block_throughput"])
peak_y = best["block_throughput"]
peak_x = best["offered_block_throughput"]
if not peak_header_added:
peak_annotations.append(
dict(
x=_log10(label_x),
y=_log10(peak_y),
xref="x",
yref="y",
text="PEAK THROUGHPUT",
showarrow=False,
xanchor="center",
yanchor="bottom",
yshift=24,
font=dict(
family=tokens["typography"]["font_family"],
size=10,
color="#ffffff",
),
)
)
peak_header_added = True
label_text = f"<b>{_fmt_si(peak_y)}</b>"
peak_annotations.append(
dict(
x=_log10(label_x),
y=_log10(peak_y),
xref="x",
yref="y",
text=label_text,
showarrow=False,
xanchor="center",
yanchor="bottom",
yshift=6,
font=dict(
family=tokens["typography"]["font_family_mono"],
size=12,
color=color,
),
)
)
if version:
peak_annotations.append(
dict(
x=_log10(label_x),
y=_log10(peak_y),
xref="x",
yref="y",
text=f"<b>{version}</b>",
showarrow=False,
xanchor="center",
yanchor="top",
yshift=4,
font=dict(
family=tokens["typography"]["font_family"],
size=9,
color=color,
),
opacity=1.0,
)
)
peak_values[name] = peak_y
y_up = peak_y * 1.06
peak_shapes.append(
dict(
type="line",
xref="x",
yref="y",
x0=peak_x,
x1=label_x,
y0=y_up,
y1=y_up,
line=dict(color=color, width=2, dash="dot"),
layer="above",
)
)
# ] bracket from pixel editor (bracket_editor_px.html)
# Pixel coords on 775x650 canvas → Plotly paper-x / data-y
top_peak = peak_values.get("nested-map", 170e6)
if "nested-map" not in peak_values:
warnings.warn("nested-map not in data; using fallback 170M")
bot_peak = peak_values.get("radix-tree", 4e6)
if "radix-tree" not in peak_values:
warnings.warn("radix-tree not in data; using fallback 4M")
improvement = top_peak / bot_peak
_margin_l, _margin_r, _margin_t, _margin_b = 60, 55, 70, 60
_plot_w = args.width - _margin_l - _margin_r
_plot_h = args.height - _margin_t - _margin_b
_y_log_lo = _log10(axis_min)
_y_log_hi = _log10(y_max)
def _px_to_paper_x(px: float) -> float:
return float((px - _margin_l) / _plot_w)
def _px_to_data_y(px: float) -> float:
frac = (_margin_t + _plot_h - px) / _plot_h
return float(10 ** (_y_log_lo + frac * (_y_log_hi - _y_log_lo)))
br_x = 723
br_y_top = 131
br_y_bot = 369
br_tick = 16
br_lx_shift = 6
bx_paper = _px_to_paper_x(br_x)
tick_paper = br_tick / _plot_w
top_y = _px_to_data_y(br_y_top)
bot_y = _px_to_data_y(br_y_bot)
mid_y = _px_to_data_y((br_y_top + br_y_bot) / 2)
for y_val in [top_y, bot_y]:
peak_shapes.append(
dict(
type="line",
xref="paper",
yref="y",
x0=bx_paper,
x1=bx_paper - tick_paper,
y0=y_val,
y1=y_val,
line=dict(color="#cdcdcd", width=1.5),
layer="above",
)
)
peak_shapes.append(
dict(
type="line",
xref="paper",
yref="y",
x0=bx_paper,
x1=bx_paper,
y0=bot_y,
y1=top_y,
line=dict(color="#cdcdcd", width=1.5),
layer="above",
)
)
peak_annotations.append(
dict(
xref="paper",
yref="y",
x=bx_paper,
y=_log10(mid_y),
text=f"{improvement:.0f}×", # noqa: RUF001
showarrow=False,
xanchor="left",
xshift=br_lx_shift,
font=dict(
family=tokens["typography"]["font_family"],
size=10,
color="#ffffff",
),
)
)
fig.update_layout(
template=template,
title=dict(text="ACHIEVED VS. OFFERED THROUGHPUT (HIGHER IS BETTER)"),
xaxis=dict(
title="Offered Throughput (block ops/s)",
type="log",
range=[_log10(axis_min), _log10(x_max)],
tickformat=".2s",
),
yaxis=dict(
title="Achieved Throughput (block ops/s)",
type="log",
range=[_log10(axis_min), _log10(y_max)],
tickformat=".2s",
),
legend=dict(
x=0.02,
y=0.98,
xanchor="left",
yanchor="top",
),
width=args.width,
height=args.height,
margin=dict(l=_margin_l, r=_margin_r, t=_margin_t, b=_margin_b),
annotations=peak_annotations,
shapes=peak_shapes,
)
out = Path(args.output)
out.parent.mkdir(parents=True, exist_ok=True)
png = out.with_suffix(".png")
svg = out.with_suffix(".svg")
fig.write_image(str(png), scale=3)
fig.write_image(str(svg))
print(f"Wrote {png.name} ({args.width}x{args.height})")
print(f"Wrote {svg.name} ({args.width}x{args.height})")
def _log10(x: float) -> float:
return math.log10(x)
def _fmt_si(v: float) -> str:
if v >= 1e9:
return f"{v / 1e9:.1f}G"
if v >= 1e6:
return f"{v / 1e6:.0f}M"
if v >= 1e3:
return f"{v / 1e3:.0f}K"
return f"{v:.0f}"
if __name__ == "__main__":
main()
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Inject legends and apply padding to Flash Indexer SVGs.
Reads each diagram SVG, adjusts the viewBox for padding, and injects
a legend group at the specified coordinates. Fully idempotent: uses
marker comments to strip previous injections before re-applying.
Coordinates were captured with the interactive legend_editor.py tool.
Usage:
python3 inject_legends.py
"""
import re
from pathlib import Path
from typing import Any
HERE = Path(__file__).parent
OUT = HERE.parent / "images"
ROW_H = 22
LABEL_W = 80
LINE_W = 40
ARROW_W = 6
PAD = 8
# Marker comments for idempotent injection
BG_START = "<!-- INJ:BG -->"
BG_END = "<!-- /INJ:BG -->"
LEG_START = "<!-- INJ:LEGEND -->"
LEG_END = "<!-- /INJ:LEGEND -->"
ORIG_VB_ATTR = "data-orig-vb"
CONFIG: dict[str, dict[str, Any]] = {
"event-flow": {
"file": "event-flow.svg",
"out": "fig-2-kv-event-flow.svg",
"legend": {"x": 823, "y": 50},
"padding": {"top": -50, "right": -75, "bottom": -50, "left": -76},
"entries": [
("Data Flow", "#c4a035", "solid"),
("Control Flow", "#5a90c0", "dashed"),
],
},
"radix-tree": {
"file": "radix-tree.svg",
"out": "fig-3-prefix-tree.svg",
"legend": {"x": 315, "y": 100},
"padding": {"top": -65, "right": 10, "bottom": -65, "left": -10},
"entries": [("Traversal", "#e0e0e0", "dotted")],
},
"write-read-path": {
"file": "write-read-path.svg",
"out": "fig-4-concurrency-model.svg",
"legend": {"x": 831, "y": 16},
"padding": {"top": -7, "right": -25, "bottom": -21, "left": -25},
"entries": [
("Data Flow", "#c4a035", "solid"),
("Control Flow", "#5a90c0", "dashed"),
("Contention", "#d06060", "solid"),
],
},
"jump-search": {
"file": "jump-search.svg",
"out": "fig-5-jump-search.svg",
"legend": {"x": 588, "y": -42},
"padding": {"top": 22, "right": 22, "bottom": 22, "left": 22},
"entries": [("Traversal", "#e0e0e0", "dotted")],
},
}
def build_legend_group(entries: list[tuple[str, str, str]], x: int, y: int) -> str:
"""Build SVG elements for a legend at the given position."""
parts = [
f'<g transform="translate({x},{y})">',
]
for i, (label, color, style) in enumerate(entries):
ey = PAD + i * ROW_H + 14
parts.append(
f'<text x="{PAD}" y="{ey}" fill="{color}" font-size="13" '
f'font-family="Helvetica, Arial, sans-serif">{label}</text>'
)
lx = PAD + LABEL_W
dash = ""
if style == "dashed":
dash = ' stroke-dasharray="6,4"'
elif style == "dotted":
dash = ' stroke-dasharray="3,4"'
parts.append(
f'<line x1="{lx}" y1="{ey - 4}" x2="{lx + LINE_W}" y2="{ey - 4}" '
f'stroke="{color}" stroke-width="2"{dash}/>'
)
ax = lx + LINE_W + 4
ay = ey - 4
parts.append(
f'<polygon points="{ax},{ay - 4} {ax},{ay + 4} {ax + ARROW_W},{ay}" fill="{color}"/>'
)
parts.append("</g>")
return "".join(parts)
def strip_injections(svg: str) -> str:
"""Remove all previously injected content and restore original viewBox."""
svg = re.sub(
re.escape(BG_START) + r".*?" + re.escape(BG_END),
"",
svg,
flags=re.DOTALL,
)
svg = re.sub(
re.escape(LEG_START) + r".*?" + re.escape(LEG_END),
"",
svg,
flags=re.DOTALL,
)
m = re.search(rf'{ORIG_VB_ATTR}="([^"]*)"', svg)
if m:
orig_vb = m.group(1)
svg = re.sub(rf'\s*{ORIG_VB_ATTR}="[^"]*"', "", svg)
svg = re.sub(r'viewBox="[^"]*"', f'viewBox="{orig_vb}"', svg, count=1)
return svg
def inject(svg: str, cfg: dict) -> str:
"""Inject legend and padding into an SVG string."""
svg = strip_injections(svg)
vb_m = re.search(r'viewBox="([^"]*)"', svg)
if not vb_m:
raise ValueError("No viewBox found in SVG")
orig_vb = vb_m.group(1)
vbx, vby, vbw, vbh = (float(v) for v in orig_vb.split())
p = cfg["padding"]
nx = vbx - p["left"]
ny = vby - p["top"]
nw = vbw + p["left"] + p["right"]
nh = vbh + p["top"] + p["bottom"]
new_vb = f"{nx:g} {ny:g} {nw:g} {nh:g}"
svg = re.sub(
r'viewBox="[^"]*"',
f'viewBox="{new_vb}" {ORIG_VB_ATTR}="{orig_vb}"',
svg,
count=1,
)
bg_rect = (
f'{BG_START}<rect x="{nx:g}" y="{ny:g}" width="{nw:g}" height="{nh:g}" '
f'fill="#0a0a0a"/>{BG_END}'
)
legend = build_legend_group(cfg["entries"], cfg["legend"]["x"], cfg["legend"]["y"])
legend_block = f"{LEG_START}{legend}{LEG_END}"
nested = "</svg></svg>" in svg
if nested:
inner_pos = svg.index("<svg", svg.index("<svg") + 1)
svg = svg[:inner_pos] + bg_rect + svg[inner_pos:]
# Insert legend in the OUTER svg (between inner </svg> and outer </svg>)
outer_close = svg.rfind("</svg></svg>") + len("</svg>")
svg = svg[:outer_close] + legend_block + svg[outer_close:]
else:
open_end = svg.index(">", svg.index("<svg")) + 1
svg = svg[:open_end] + bg_rect + svg[open_end:]
close_pos = svg.rfind("</svg>")
svg = svg[:close_pos] + legend_block + svg[close_pos:]
return svg
def main() -> None:
OUT.mkdir(parents=True, exist_ok=True)
for cfg in CONFIG.values():
src = HERE / cfg["file"]
if not src.exists():
print(f" SKIP: {cfg['file']} not found")
continue
svg = src.read_text()
result = inject(svg, cfg)
dst = OUT / cfg["out"]
dst.write_text(result)
p = cfg["padding"]
print(
f" {cfg['file']} -> {cfg['out']}: legend at ({cfg['legend']['x']}, {cfg['legend']['y']}), "
f"padding T{p['top']:+d} R{p['right']:+d} B{p['bottom']:+d} L{p['left']:+d}"
)
if __name__ == "__main__":
main()
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Dynamo Dark theme for Plotly charts.
Loads design tokens from design_tokens.yaml and produces a reusable
plotly.graph_objects.layout.Template aligned with the Dynamo visual identity.
Typography:
- Titles, headings, body: Arial (sans-serif)
- Tick labels, code-like text: Roboto Mono (monospace fallback)
Usage:
from plotly_dynamo import dynamo_template, load_tokens
fig = go.Figure(data=[...], layout=go.Layout(template=dynamo_template))
fig.write_image("chart.svg")
fig.write_image("chart.png", scale=2)
Or apply globally:
import plotly.io as pio
pio.templates.default = dynamo_template
"""
from __future__ import annotations
from pathlib import Path
from typing import Any
import plotly.graph_objects as go
import yaml
def load_tokens(path: str | Path | None = None) -> dict[str, Any]:
"""Load design tokens from YAML file.
Args:
path: Path to design_tokens.yaml. Defaults to the file
next to this module.
Returns:
Parsed token dictionary.
"""
if path is None:
path = Path(__file__).parent / "design_tokens.yaml"
with open(path) as f:
return yaml.safe_load(f)
def build_template(tokens: dict[str, Any] | None = None) -> go.layout.Template:
"""Build a Plotly Template from design tokens.
Args:
tokens: Parsed design_tokens dict. Loaded from default path if None.
Returns:
A fully configured plotly.graph_objects.layout.Template.
"""
if tokens is None:
tokens = load_tokens()
colors = tokens["colors"]
typo = tokens["typography"]
bg_primary = colors["background"]["primary"]
text_primary = colors["text"]["primary"]
text_secondary = colors["text"]["secondary"]
border_subtle = colors["border"]["subtle"]
series = colors["chart_series"]
font_sans = typo["font_family"]
font_mono = typo["font_family_mono"] # Roboto Mono for ticks/code
layout = go.Layout(
# -- Background --
paper_bgcolor=bg_primary,
plot_bgcolor=bg_primary,
# -- Typography --
font=dict(
family=font_sans,
color=text_primary,
size=typo["label"]["size"],
),
title=dict(
font=dict(
family=font_sans,
size=typo["title"]["size"],
color=text_primary,
),
x=0.02,
xanchor="left",
y=0.98,
yanchor="top",
),
# -- Color palette --
colorway=series,
# -- X axis (monospace tick labels) --
xaxis=dict(
gridcolor=border_subtle,
gridwidth=0.5,
zeroline=False,
linecolor=border_subtle,
linewidth=0.5,
tickfont=dict(
family=font_mono,
size=typo["annotation"]["size"],
color=text_secondary,
),
title=dict(
font=dict(
family=font_sans,
size=typo["label"]["size"],
color=text_secondary,
),
),
),
# -- Y axis (monospace tick labels for alignment) --
yaxis=dict(
gridcolor=border_subtle,
gridwidth=0.5,
zeroline=False,
linecolor=border_subtle,
linewidth=0.5,
tickfont=dict(
family=font_mono,
size=typo["label"]["size"],
color=text_primary,
),
title=dict(
font=dict(
family=font_sans,
size=typo["label"]["size"],
color=text_secondary,
),
),
automargin=True,
),
# -- Legend --
legend=dict(
bgcolor="rgba(0,0,0,0)",
font=dict(
family=font_sans,
size=typo["annotation"]["size"],
color=text_secondary,
),
bordercolor=border_subtle,
borderwidth=0,
),
# -- Margins --
margin=dict(l=20, r=20, t=60, b=20),
# -- Subtle outer frame (muted green, thin) --
shapes=[
dict(
type="rect",
xref="paper",
yref="paper",
x0=-0.01,
y0=-0.02,
x1=1.01,
y1=1.04,
line=dict(
color=border_subtle,
width=0.5,
),
fillcolor="rgba(0,0,0,0)",
layer="above",
),
],
)
# -- Data defaults --
template = go.layout.Template(layout=layout)
# Bar chart defaults
template.data.bar = [
go.Bar(
marker=dict(
line=dict(width=0),
opacity=0.92,
),
textfont=dict(
family=font_mono,
size=typo["annotation"]["size"],
color=text_primary,
),
textposition="inside",
insidetextanchor="start",
error_x=dict(
color=text_primary,
thickness=1.5,
width=4,
),
error_y=dict(
color=text_primary,
thickness=1.5,
width=4,
),
),
]
# Scatter / line chart defaults
template.data.scatter = [
go.Scatter(
marker=dict(size=8, line=dict(width=1, color=bg_primary)),
line=dict(width=2),
),
]
return template
# Module-level singleton -- import this directly
dynamo_template = build_template()
def apply_outer_frame(fig: go.Figure) -> go.Figure:
"""Add the Dynamo green outer frame to an existing figure.
Useful when creating a figure without the template, or when
the frame was lost during updates.
"""
tokens = load_tokens()
border_frame = tokens["colors"]["border"]["frame"]
frame_width = tokens["borders"]["frame_width"]
fig.add_shape(
type="rect",
xref="paper",
yref="paper",
x0=-0.01,
y0=-0.02,
x1=1.01,
y1=1.04,
line=dict(color=border_frame, width=frame_width),
fillcolor="rgba(0,0,0,0)",
layer="above",
)
return fig
def section_annotation(
fig: go.Figure,
text: str,
y: float,
x: float = 0.0,
) -> go.Figure:
"""Add a section header annotation (e.g., 'DISPATCH (us)').
Uses the Dynamo theme font for section headers.
Args:
fig: The Plotly figure.
text: Section header text (pre-formatted; not auto-uppercased).
y: Y position in paper coordinates (0-1).
x: X position in paper coordinates (0-1).
"""
tokens = load_tokens()
typo = tokens["typography"]
text_color = tokens["colors"]["text"]["secondary"]
fig.add_annotation(
text=text,
xref="paper",
yref="paper",
x=x,
y=y,
showarrow=False,
font=dict(
family=typo["font_family"],
size=typo["heading"]["size"],
color=text_color,
),
xanchor="left",
yanchor="bottom",
)
return fig
# Flash Indexer: Radix Tree (with workers, depth gradient, edge labels added in post)
# Layout: ELK (better for pure tree structures; TALA places nodes non-deterministically)
...@theme.d2
direction: down
root: Root { class: neutral }
b0: "Block 0\nW0, W1, W2" { class: depth_0 }
b0p: "Block 0'\nW3" { class: depth_0 }
b1: "Block 1\nW0, W1, W2" { class: depth_1 }
b2: "Block 2\nW0, W1" { class: depth_2 }
b2p: "Block 2'\nW2" { class: depth_2 }
b3: "Block 3\nW0" { class: depth_3 }
root -> b0 { class: traversal }
root -> b0p { class: traversal }
b0 -> b1 { class: traversal }
b1 -> b2 { class: traversal }
b1 -> b2p { class: traversal }
b2 -> b3 { class: traversal }
# Dynamo Dark Theme for D2
# Import into sibling diagrams: ...@theme.d2
#
# Design: Muted fills, subtle borders, selective accent color.
# Color palette from design_tokens.yaml
# ---------------------------------------------------------------------------
# Theme overrides
# ---------------------------------------------------------------------------
vars: {
d2-config: {
theme-overrides: {
# Neutral shades -- dark background
N1: "#e0e0e0"
N2: "#a0a0a0"
N3: "#707070"
N4: "#404040"
N5: "#5d5d5d"
N6: "#151515"
N7: "#0a0a0a"
# Base colors -- container nesting
B1: "#0a0a0a"
B2: "#111111"
B3: "#181818"
B4: "#222222"
B5: "#5d5d5d"
B6: "#404040"
# Accents
AA2: "#76b900"
AA4: "#3d7ab5"
AA5: "#c4a035"
AB4: "#7a3050"
AB5: "#2a6b55"
}
}
}
# ---------------------------------------------------------------------------
# Reusable classes
# ---------------------------------------------------------------------------
classes: {
# --- Hardware components (outlined style with muted accent) ---
gpu: {
style: {
opacity: 0.75
fill: "#151515"
stroke: "#4a8c00"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
nic: {
style: {
opacity: 0.75
fill: "#2a1520"
stroke: "#7a3050"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
cpu: {
style: {
opacity: 0.75
fill: "#0f1e30"
stroke: "#3d7ab5"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
# --- Logical components (selective accent fills) ---
data_component: {
style: {
opacity: 0.75
fill: "#2a4a10"
stroke: "#5a9a30"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
flag_component: {
style: {
opacity: 0.75
fill: "#1e1a14"
stroke: "#7a6a45"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
# --- Depth gradient (radix tree levels, desaturated green) ---
depth_0: {
style: {
opacity: 0.75
fill: "#2a4a10"
stroke: "#5a9a30"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
depth_1: {
style: {
opacity: 0.75
fill: "#224010"
stroke: "#4a8828"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
depth_2: {
style: {
opacity: 0.75
fill: "#1a3510"
stroke: "#3a7520"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
depth_3: {
style: {
opacity: 0.75
fill: "#142a0c"
stroke: "#2c6018"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
# --- Software / Service components ---
service: {
style: {
opacity: 0.75
fill: "#1a1428"
stroke: "#7650a0"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
api: {
style: {
opacity: 0.75
fill: "#1a1428"
stroke: "#8060b0"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
database: {
style: {
opacity: 0.75
fill: "#142025"
stroke: "#3a7a70"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
cache: {
style: {
opacity: 0.75
fill: "#142025"
stroke: "#50a090"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
queue: {
style: {
opacity: 0.75
fill: "#201810"
stroke: "#a06040"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
event: {
style: {
opacity: 0.75
fill: "#201810"
stroke: "#c08050"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
# --- Infrastructure / Deployment ---
container_runtime: {
style: {
opacity: 0.75
fill: "#101820"
stroke: "#4080a0"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
load_balancer: {
style: {
opacity: 0.75
fill: "#1a1a10"
stroke: "#909040"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
endpoint: {
style: {
opacity: 0.75
fill: "#151515"
stroke: "#616161"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
# --- Status / Semantic ---
critical: {
style: {
opacity: 0.75
fill: "#2a1010"
stroke: "#b04040"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
success: {
style: {
opacity: 0.75
fill: "#102010"
stroke: "#40a040"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
bold: true
}
}
neutral: {
style: {
opacity: 0.75
fill: "#1a1a1a"
stroke: "#636363"
stroke-width: 1
border-radius: 0
font-color: "#e0e0e0"
font-size: 16
}
}
# --- Containers (subtle, receding) ---
outer_frame: {
style: {
fill: "#0a0a0a"
stroke: "#5d5d5d"
stroke-width: 1
font-color: "#e0e0e0"
font-size: 20
bold: true
}
}
container_l1: {
style: {
fill: "#111111"
stroke: "#616161"
stroke-width: 1
border-radius: 0
font-color: "#c0c0c0"
font-size: 18
bold: true
}
}
container_l2: {
style: {
fill: "#181818"
stroke: "#666666"
stroke-width: 1
border-radius: 0
font-color: "#a0a0a0"
font-size: 16
}
}
container_l3: {
style: {
fill: "#1e1e1e"
stroke: "#6a6a6a"
stroke-width: 1
border-radius: 0
font-color: "#909090"
font-size: 14
}
}
# --- Text elements ---
section_title: {
shape: text
style: {
font-size: 20
bold: true
font-color: "#e0e0e0"
}
}
annotation: {
shape: text
style: {
font-size: 14
font-color: "#8a8a8a"
italic: true
}
}
# --- Connection types (muted, thin) ---
data_flow: {
style: {
stroke: "#c4a035"
stroke-width: 2
font-color: "#c4a035"
font-size: 14
}
}
control_flow: {
style: {
stroke: "#3d7ab5"
stroke-width: 1
stroke-dash: 4
font-color: "#5a90c0"
font-size: 14
}
}
poll_flow: {
style: {
stroke: "#4a8c00"
stroke-width: 1
stroke-dash: 3
opacity: 0.5
font-color: "#4a8c00"
font-size: 14
}
}
nvlink: {
style: {
stroke: "#c4a035"
stroke-width: 2
font-color: "#c4a035"
font-size: 14
}
}
rdma_flow: {
style: {
stroke: "#7a3050"
stroke-width: 2
font-color: "#c06080"
font-size: 14
}
}
# --- Software / Pipeline connections ---
api_call: {
style: {
stroke: "#6a4890"
stroke-width: 1
font-color: "#9070c0"
font-size: 14
}
}
event_flow: {
style: {
stroke: "#a06040"
stroke-width: 1
stroke-dash: 4
font-color: "#c08050"
font-size: 14
}
}
pipeline: {
style: {
stroke: "#3a7a70"
stroke-width: 2
font-color: "#50a090"
font-size: 14
}
}
dependency: {
style: {
stroke: "#767676"
stroke-width: 1
stroke-dash: 3
font-color: "#8a8a8a"
font-size: 14
}
}
critical_path: {
style: {
stroke: "#b04040"
stroke-width: 2
font-color: "#d06060"
font-size: 14
}
}
traversal: {
style: {
stroke: "#e0e0e0"
stroke-width: 1
stroke-dash: 2
font-color: "#c0c0c0"
font-size: 14
}
}
}
# Flash Indexer: Write/Read Path (grid layout with containers)
# Tree placed inside Read Path for grid alignment; container border
# adjusted in SVG post-processing to exclude it.
# Read Lock label + arrow added in SVG post-processing.
...@theme.d2
direction: right
writes: Write Path {
class: container_l1
grid-rows: 3
grid-gap: 150
ev: KV Events {
shape: queue
class: event
width: 300
height: 72
}
sr: Sticky Router {
class: load_balancer
width: 300
height: 72
}
pool: "Thread Pool (x3)" {
class: cpu
width: 300
height: 72
}
ev -> sr { class: data_flow }
sr -> pool { class: control_flow }
}
reads: Read Path {
class: container_l1
grid-rows: 3
grid-gap: 150
req: Incoming Request {
shape: hexagon
class: neutral
width: 300
height: 72
}
fm: "find_matches()" {
class: api
width: 300
height: 72
}
tree: Concurrent Radix Tree {
shape: cylinder
class: database
width: 300
height: 72
}
req -> fm { class: control_flow }
}
writes.pool -> reads.tree: Write Lock { class: critical_path }
...@@ -6,5 +6,12 @@ description: Technical deep dives, announcements, and updates from the Dynamo te ...@@ -6,5 +6,12 @@ description: Technical deep dives, announcements, and updates from the Dynamo te
Technical deep dives, announcements, and updates from the Dynamo team. Technical deep dives, announcements, and updates from the Dynamo team.
<CardGroup cols={2}> <CardGroup cols={2}>
{/* Add blog post cards here. See README.md in this folder for instructions. */} <Card
title="Flash Indexer: Inter-Galactic KV Routing"
icon="regular bolt"
href="/dynamo/dev/blog/flash-indexer"
>
How Dynamo's concurrent global index evolved through six iterations to sustain
over 100 million operations per second.
</Card>
</CardGroup> </CardGroup>
...@@ -42,6 +42,8 @@ navbar-links: ...@@ -42,6 +42,8 @@ navbar-links:
links: links:
- text: All Posts - text: All Posts
href: /dynamo/dev/blog href: /dynamo/dev/blog
- text: "Flash Indexer: Inter-Galactic KV Routing"
href: /dynamo/dev/blog/flash-indexer
- type: github - type: github
value: https://github.com/ai-dynamo/dynamo value: https://github.com/ai-dynamo/dynamo
......
...@@ -429,6 +429,21 @@ animation-range: 0 50px; ...@@ -429,6 +429,21 @@ animation-range: 0 50px;
background-color: transparent !important; background-color: transparent !important;
transition: box-shadow 0.3s ease, outline 0.3s ease; transition: box-shadow 0.3s ease, outline 0.3s ease;
} }
/* Figure caption callouts */
.fig-caption {
--callout-border: transparent !important;
--callout-icon-color: var(--grayscale-a8) !important;
background-color: var(--nv-light-grey-1) !important;
font-size: 0.875rem;
}
.dark .fig-caption {
background-color: var(--nv-dark-grey-2) !important;
}
.fig-caption p {
font-style: italic;
color: var(--tw-prose-body) !important;
}
/* Hide line numbers */ /* Hide line numbers */
.code-block-line-gutter { .code-block-line-gutter {
display: none !important; display: none !important;
......
...@@ -224,7 +224,10 @@ navigation: ...@@ -224,7 +224,10 @@ navigation:
- section: Blog - section: Blog
path: ../blogs/index.mdx path: ../blogs/index.mdx
slug: blog slug: blog
contents: [] contents:
- page: "Flash Indexer: Inter-Galactic KV Routing"
path: ../blogs/flash-indexer/flash-indexer.md
slug: flash-indexer
# ==================== Hidden Pages ==================== # ==================== Hidden Pages ====================
# Pages accessible via direct URL but not shown in main navigation. # Pages accessible via direct URL but not shown in main navigation.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment