analytical-viz: roofline tab — headline step-latency + cost-per-token plots, B knob
Two new plots at the top of the Chip Roofline tab (right after the
knob row), side by side:
1. **Latency per decode step** — one forward pass's total time as B
grows. weight_fetch (flat in B), compute (linear), KV (linear),
total. The SLO / TTFT view — bigger B = longer step.
2. **Cost per token** = step latency ÷ B. weight (shrinks 1/B),
compute (flat), KV (flat), total. The efficiency / cost view —
bigger B (up to ~2·B*) = cheaper per token.
Same underlying decomposition, two divisors. Puts the classic
throughput ↔ latency tradeoff in one glance.
Also added a **B (batch size) slider** next to the existing S_kv
slider. Both plots draw a vertical marker at the current B; the
regime KPI ("memory-bound / compute-bound / kv-bound") now uses the
slider B, so you can sweep B live and watch the label flip when you
cross B*.
step_latency_curve + StepLatencyPoint added to chip_roofline; 5 new
tests cover: weight_s batch-invariant, compute_s/kv_s linear in B,
step_total == per_token_total × B (definitional), and step ==
per_token at B=1.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -256,3 +256,51 @@ def utilization_at(s_kv: int, l_star: float) -> float:
|
||||
At S_kv=0: 100%. At S_kv=L*: 50%. At 2·L*: 33.3%. At 5·L*: 16.7%.
|
||||
"""
|
||||
return 1.0 / (1.0 + s_kv / l_star)
|
||||
|
||||
|
||||
# ── Per-step latency (undivided by B) ─────────────────────────────
|
||||
|
||||
|
||||
@dataclass
|
||||
class StepLatencyPoint:
|
||||
batch: int
|
||||
weight_s: float # N·b / W — flat in B (loaded once per step)
|
||||
compute_s: float # 2·N·B / C — linear in B
|
||||
kv_s: float # B · S_kv · kv_bpt / W — linear in B
|
||||
total_s: float
|
||||
|
||||
|
||||
def step_latency_curve(machine: MachineParams, model: ModelConfig,
|
||||
batch_range: list[int],
|
||||
s_kv: int) -> list[StepLatencyPoint]:
|
||||
"""Total time of one decode step (one forward pass), across a
|
||||
range of batch sizes. NOT divided by B — this is the SLO view.
|
||||
|
||||
step_weight = N·b / W (batch-invariant)
|
||||
step_compute = 2·N·B / C (linear in B)
|
||||
step_kv = B · S_kv · kv_bpt / W (linear in B)
|
||||
|
||||
Per-token cost = step_total / B — the two views trade off:
|
||||
bigger B lowers cost/token but raises step latency.
|
||||
"""
|
||||
n_active = total_active_params(model)
|
||||
b = model.bytes_per_elem
|
||||
weight_bytes = n_active * b
|
||||
kv_bpt = kv_bytes_per_token(model)
|
||||
|
||||
step_weight = weight_bytes / machine.bw_hbm
|
||||
|
||||
points: list[StepLatencyPoint] = []
|
||||
for bs in batch_range:
|
||||
B = max(1, bs)
|
||||
step_compute = _FLOPS_PER_PARAM_PER_TOKEN * n_active * B / machine.peak_flops
|
||||
step_kv = B * s_kv * kv_bpt / machine.bw_hbm
|
||||
total = step_weight + step_compute + step_kv
|
||||
points.append(StepLatencyPoint(
|
||||
batch=bs,
|
||||
weight_s=step_weight,
|
||||
compute_s=step_compute,
|
||||
kv_s=step_kv,
|
||||
total_s=total,
|
||||
))
|
||||
return points
|
||||
|
||||
Reference in New Issue
Block a user