Skip to content

Commit fe1a55e

Browse files
test(case2): cross-host RTT-sweep mode — inject per-block proposer<->verifier round-trip into the fused engine to measure the WAN-penalty throughput curve
Co-authored-by: FluffyAIcode <FluffyAIcode@users.noreply.github.com>
1 parent dae8487 commit fe1a55e

1 file changed

Lines changed: 53 additions & 1 deletion

File tree

scripts/research/k3_specdecode_gpu_bench.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ def restored_specdecode(
169169
def restored_specdecode_fused(
170170
adapter, drafter, verifier, aux_layer_ids, embed_fn, lm_head_fn,
171171
prompt, gen_tokens, block_size, device, eos_ids,
172+
block_rtt_ms: float = 0.0,
172173
) -> Dict[str, Any]:
173174
"""FUSED spec-decode engine (A+B+C): per-block O(L).
174175
@@ -195,12 +196,21 @@ def restored_specdecode_fused(
195196

196197
generated: List[int] = []
197198
accepts: List[int] = []
198-
t_draft = t_verify = t_extend = 0.0
199+
t_draft = t_verify = t_extend = t_network = 0.0
200+
rtt_s = max(0.0, block_rtt_ms) / 1000.0
199201
torch.cuda.synchronize(device)
200202
t0 = time.perf_counter()
201203
while len(generated) < gen_tokens:
202204
L = min(block_size, gen_tokens - len(generated))
203205
cstart = adapter._past_len # committed length at block start
206+
# Cross-host model: one proposer<->verifier round-trip per block
207+
# (proposer ships the draft block to the verifier host, gets the
208+
# accept/reject + bonus back). Injected as a per-block delay so the
209+
# measured decode throughput reflects the WAN penalty on real compute.
210+
if rtt_s:
211+
tn = time.perf_counter()
212+
time.sleep(rtt_s)
213+
t_network += time.perf_counter() - tn
204214
bonus = int(adapter.next_token_logits.argmax().item())
205215
td = time.perf_counter()
206216
drafts = drafter.draft_block_cached(
@@ -252,10 +262,12 @@ def restored_specdecode_fused(
252262
"drafter_cached": round(t_draft, 3),
253263
"incremental_verify": round(t_verify, 3),
254264
"ctx_kv_extend": round(t_extend, 3),
265+
"network_rtt": round(t_network, 3),
255266
},
256267
"blocks": len(accepts),
257268
"mean_accept_len": round(sum(accepts) / len(accepts), 2) if accepts else 0.0,
258269
"decode_tokens": len(generated),
270+
"block_rtt_ms": block_rtt_ms,
259271
}
260272

261273

@@ -275,6 +287,11 @@ def main() -> int:
275287
help="Skip the un-fused restored spec-decode baseline "
276288
"(already characterized; removes GPU contention for a "
277289
"clean fused-vs-AR steady-state measurement).")
290+
ap.add_argument("--rtt-sweep", default=None,
291+
help="Comma-separated per-block RTT values (ms) to model a "
292+
"cross-host proposer<->verifier draft loop. When set, "
293+
"after the co-located run the fused path is re-timed on "
294+
"prompt[0] at each RTT — the WAN-penalty curve (Case 2).")
278295
ap.add_argument("--output", default=None)
279296
args = ap.parse_args()
280297

@@ -461,6 +478,41 @@ def recall(tokens, ans):
461478
fu_tps = report["restored_specdecode_fused"]["decode_tokens_per_s_mean"]
462479
report["restored_specdecode_fused"]["speedup_over_ar_x"] = (
463480
round(fu_tps / ar_mean, 2) if ar_mean else None)
481+
482+
# --- Case 2: cross-host proposer<->verifier WAN-penalty curve ---
483+
if args.rtt_sweep:
484+
rtts = [float(x) for x in args.rtt_sweep.split(",") if x.strip()]
485+
prompt0 = ids_list[0][0].tolist()
486+
sweep = []
487+
for rtt in rtts:
488+
r = restored_specdecode_fused(
489+
adapter, drafter, verifier, aux_layer_ids, embed_fn, lm_head_fn,
490+
prompt0, args.max_new_tokens, args.block_size, device, eos_ids,
491+
block_rtt_ms=rtt)
492+
tps = r["decode_tokens_per_s"]
493+
sweep.append({
494+
"block_rtt_ms": rtt,
495+
"decode_tokens_per_s": tps,
496+
"vs_ar_x": round(tps / ar_mean, 3) if ar_mean else None,
497+
"blocks": r["blocks"],
498+
"mean_accept_len": r["mean_accept_len"],
499+
"network_s": r["time_breakdown_s"]["network_rtt"],
500+
"decode_s": r["decode_s"],
501+
})
502+
print(f"[sd][rtt] {rtt:6.1f} ms/block -> {tps} tok/s "
503+
f"({sweep[-1]['vs_ar_x']}x AR, blocks={r['blocks']})",
504+
file=sys.stderr, flush=True)
505+
# break-even: highest RTT still >= AR (vs_ar_x >= 1.0)
506+
over_ar = [s["block_rtt_ms"] for s in sweep if (s["vs_ar_x"] or 0) >= 1.0]
507+
report["crosshost_rtt_sweep"] = {
508+
"ar_baseline_tps": ar_mean,
509+
"colocated_fused_tps": fu_tps,
510+
"sweep": sweep,
511+
"max_rtt_ms_at_or_above_ar": (max(over_ar) if over_ar else 0.0),
512+
"note": ("one proposer<->verifier round-trip per block; cloud<->desk "
513+
"RTT is typically 30-150 ms. Quantifies why the cross-host "
514+
"token-level draft data plane is WAN-infeasible."),
515+
}
464516
out_path = Path(args.output) if args.output else Path(
465517
f"results/research/k3_specdecode_gpu_bench_{int(time.time())}.json")
466518
out_path.parent.mkdir(parents=True, exist_ok=True)

0 commit comments

Comments
 (0)