Speculative decoding economics: the walltime-cost model and when it stops paying¶
Scope: production economics for speculative decoding, separate from the accept/reject mechanics in speculative decoding. It uses Leviathan, Kalman, and Matias's low-batch walltime theorem for analytical screening, then requires direct latency, throughput, goodput, and cost measurements at the intended concurrency. A practitioner EAGLE3 case study is retained as an unreplicated warning, not as validation of a general performance model.
The EAGLE3-on-Llama-3.1-8B figures come from one practitioner report and were not reproduced for this page.4 Current vLLM behavior is cited from its documentation. The analytical code implements the published theorem only; it does not model high-batch verification cost.
What it is¶
Speculative decoding's accept rule gives the expected number of output tokens per target verification round, including the correction or bonus token: τ = (1 - α^(γ+1)) / (1 - α) for independent per-token acceptance α and draft depth γ.1 It is not the expected number of accepted draft tokens. Theorem 3.8 gives the low-batch walltime improvement factor:
Here c is draft-step time divided by target-step time, γc prices the sequential draft steps, and 1 prices the target verification pass.1 Estimate c from isolated step latency under the theorem's low-batch conditions. An inverse tokens-per-second ratio is only an approximation when both measurements perform comparable one-token decode steps.
The theorem is not a high-concurrency capacity model. vLLM documents that verification's effective batch becomes batch_size * K; beyond a hardware-specific critical batch, speculative decoding can worsen time per output token.2 No single scalar interpolation is justified by these sources. Measure the complete server across offered load and use a batch-size schedule only after locating the crossover empirically.
Why use it¶
- Separate acceptance from performance.
τcan improve while latency or throughput regresses because drafting and verification consume time. - Screen drafter cost before a full deployment. The theorem exposes the low-batch crossover in
c, but production approval still depends on an end-to-end load test. - Handle the high-batch regime explicitly. vLLM's dynamic schedule reduces
Kas concurrency rises because verification work scales withbatch_size * K.2 - Price measured capacity, not an analytical latency ratio. Cost per output token must use aggregate accepted-output throughput under the same offered load and SLO.
When to use it (and when not)¶
Reuse speculative decoding's general go/no-go rules; this page adds the cost-side checks specifically:
- Use the theorem to reject a costly draft/target pair in low-batch decode before investing in a larger benchmark.
- Use direct A/B load tests to compare TTFT, TPOT, request goodput, accepted output tokens per second, GPU memory, and power at the intended concurrency.
- Use cost analysis when the drafter changes the GPU count, instance type, memory headroom, or power envelope.
- Avoid static speculation depth beyond the measured high-batch crossover. Reduce
Kor disable speculation for that load range. - Do not transfer paper speedups. The EAGLE-3 paper's results and the practitioner regression use different protocols and do not predict a third deployment.34
Architecture¶
flowchart TB
M["Measure alpha and c<br/>under low-batch decode"] --> T["Screen with Theorem 3.8<br/>S = tau / (gamma*c + 1)"]
T --> D{"Low-batch<br/>candidate?"}
D -->|"no"| STOP["Do not enable speculation here,<br/>or pick a cheaper/better drafter"]
D -->|"yes"| LOAD["A/B test complete server<br/>across offered load"]
LOAD --> ECON["Price measured output throughput<br/>under the same SLO"]
ECON --> G{"Net $/token<br/>improves?"}
G -->|"no"| STOP
G -->|"yes"| DEPLOY["Deploy behind a batch-size schedule<br/>(num_speculative_tokens_per_batch_size)"]
DEPLOY --> MON["Monitor acceptance, TPOT, goodput,<br/>output throughput, and $/token"]
The analytical screen below implements Theorem 3.8 and checks it against Monte Carlo sampling. It makes no high-batch claim:
# Runnable on system python3 (numpy). Leviathan et al.'s Theorem 3.8
# walltime-improvement factor, cross-checked against Monte Carlo sampling.
import numpy as np
def tau(alpha, gamma):
"""Expected output tokens per verification round, including correction/bonus."""
assert 0.0 <= alpha <= 1.0 and gamma >= 1
if alpha == 1.0:
return float(gamma + 1)
return (1.0 - alpha ** (gamma + 1)) / (1.0 - alpha)
def walltime_speedup(alpha, gamma, c):
"""Theorem 3.8; valid only under the paper's cost assumptions."""
assert c >= 0.0
return tau(alpha, gamma) / (gamma * c + 1.0)
def simulate_walltime(alpha, gamma, c, n, rng):
"""Monte Carlo reference using the theorem's constant per-round cost."""
accepts = rng.random((n, gamma)) < alpha
leading = np.cumprod(accepts, axis=1).sum(axis=1)
tokens_per_round = leading + 1
sd_time = n * (gamma * c + 1.0)
ar_time_for_same_tokens = tokens_per_round.sum()
return ar_time_for_same_tokens / sd_time
rng = np.random.default_rng(3)
# 1. Monte Carlo converges to Theorem 3.8 for several parameter sets.
for alpha, gamma, c in [(0.7, 4, 0.1), (0.5, 3, 0.3), (0.9, 6, 0.05)]:
mc = simulate_walltime(alpha, gamma, c, n=300_000, rng=rng)
cf = walltime_speedup(alpha, gamma, c)
assert abs(mc - cf) < 0.02, (alpha, gamma, c, mc, cf)
# 2. Boundaries include one correction token at alpha=0 and all draft tokens
# plus the bonus token at alpha=1.
assert tau(0.0, 4) == 1.0
assert tau(1.0, 4) == 5.0
# 3. The analytical break-even cost is c* = (tau - 1) / gamma.
alpha, gamma = 0.75, 4
c_star = (tau(alpha, gamma) - 1.0) / gamma
assert walltime_speedup(alpha, gamma, c_star - 1e-6) > 1.0
assert abs(walltime_speedup(alpha, gamma, c_star) - 1.0) < 1e-12
assert walltime_speedup(alpha, gamma, c_star + 1e-6) < 1.0
# 4. Raising drafter cost must strictly reduce the theorem's speedup.
cs = np.linspace(0.02, 1.0, 50)
speedups = np.array([walltime_speedup(alpha, gamma, c) for c in cs])
assert np.all(np.diff(speedups) < 0)
print("Theorem 3.8 walltime model: PASS")
print(f" alpha=0.75, gamma=4 analytical c*={c_star:.6f}")
Executed output:
How to use it¶
Use a measured batch-size schedule. Current vLLM accepts inclusive [start_bs, end_bs, K] ranges in num_speculative_tokens_per_batch_size; K = 0 disables drafting in that range.2 The following values are illustrative reference inputs, not recommendations:
# Reference template (needs vllm installed + a GPU). Not executed here.
from vllm import LLM
LLM(
model="<target-model>",
speculative_config={
"method": "eagle3",
"model": "<eagle3-head-repo-or-path>",
"num_speculative_tokens": 5,
# Illustrative only; cover the server's configured maximum batch size.
# These ranges must come from an A/B load test.
"num_speculative_tokens_per_batch_size": [[1, 32, 5], [33, 96, 2], [97, 512, 0]],
},
)
Current vLLM documents dynamic scheduling as tested with EAGLE, EAGLE-3, and DFlash. It is not compatible with data parallelism: vLLM disables the dynamic schedule under DP and falls back to static num_speculative_tokens to avoid collective divergence.2 Validate method, runner, parallelism, and version compatibility before rollout.
The $/token production decision. Use the measured aggregate accepted-output throughput multiplier M from an A/B load test at the same offered load and SLO. Do not substitute the theorem's single-stream walltime factor. Price any changed GPU count, instance type, or power allocation:
# Runnable on system python3 (numpy). Turns the cost formula
# (cost per 1M tokens = pod $/hr * 1e6 / (tokens/sec * 3600)) into a go/no-go
# decision using a measured accepted-output throughput multiplier M.
import numpy as np
def cost_per_million_tokens(pod_dollars_per_hr, tokens_per_sec):
assert pod_dollars_per_hr > 0 and tokens_per_sec > 0
return pod_dollars_per_hr * 1_000_000 / (tokens_per_sec * 3600)
def speculative_cost_per_million(pod_dollars_per_hr_baseline, tokens_per_sec_baseline,
throughput_multiplier, extra_dollars_per_hr=0.0):
"""Price measured aggregate output throughput and changed hourly cost."""
assert throughput_multiplier > 0
new_rate = tokens_per_sec_baseline * throughput_multiplier
new_cost_per_hr = pod_dollars_per_hr_baseline + extra_dollars_per_hr
return cost_per_million_tokens(new_cost_per_hr, new_rate)
def breakeven_extra_dollars(pod_dollars_per_hr_baseline, throughput_multiplier):
"""Extra $/hr that exactly cancels measured throughput multiplier M."""
return pod_dollars_per_hr_baseline * (throughput_multiplier - 1.0)
base = cost_per_million_tokens(pod_dollars_per_hr=2.00, tokens_per_sec=45.0)
# 1. Higher measured throughput (M>1) at the same hourly cost lowers $/token.
better = speculative_cost_per_million(2.00, 45.0, throughput_multiplier=1.8)
assert better < base
# 2. Lower accepted-output throughput makes $/token worse.
worse = speculative_cost_per_million(2.00, 45.0, throughput_multiplier=0.85)
assert worse > base
# 3. A throughput gain can still lose after pricing changed hardware.
nominal_win_but_pricier_box = speculative_cost_per_million(
2.00, 45.0, throughput_multiplier=1.15, extra_dollars_per_hr=1.20)
assert nominal_win_but_pricier_box > base
# 4. The break-even boundary is exact.
be = breakeven_extra_dollars(2.00, throughput_multiplier=1.8)
at_breakeven = speculative_cost_per_million(2.00, 45.0, 1.8, be)
assert abs(at_breakeven - base) < 1e-9
assert speculative_cost_per_million(2.00, 45.0, 1.8, be * 0.5) < base
assert speculative_cost_per_million(2.00, 45.0, 1.8, be * 1.5) > base
# 5. Boundary: unchanged throughput and hourly cost reproduce the baseline.
assert abs(speculative_cost_per_million(2.00, 45.0, 1.0, 0.0) - base) < 1e-12
print("Dollar-per-token model: PASS")
print(f" base=${base:.2f}/M tok; M=1.8x same-cost -> ${better:.2f}")
print(f" M=0.85x -> ${worse:.2f}; M=1.15x plus $1.20/hr -> ${nominal_win_but_pricier_box:.2f}")
print(f" break-even extra at M=1.8x: ${be:.2f}/hr")
Executed output:
Dollar-per-token model: PASS
base=$12.35/M tok; M=1.8x same-cost -> $6.86
M=0.85x -> $14.52; M=1.15x plus $1.20/hr -> $17.18
break-even extra at M=1.8x: $1.60/hr
How to develop with it¶
- Measure
cfrom comparable decode steps. Use draft-step time divided by target-step time in the low-batch regime. The inverse tokens-per-second ratio is an approximation only when both tests perform comparable one-token steps. - Measure
αper traffic domain, not as one global average. Acceptance rate is workload-dependent; evaluating speculative decoding (SPEED-Bench) covers the standardized methodology for measuring it across domains and input-length buckets, which feeds directly into this page'sτ(α, γ)term. - Sweep offered load with speculation on and off. Record TTFT, TPOT, request goodput, aggregate accepted-output tokens per second, memory use, and power. Locate the crossover directly instead of fitting an unsupported scalar.
How to maintain it¶
- Re-measure
cand the compute-bound crossover on any GPU generation or model swap. Both the baseline single-stream tokens/sec and the memory-bandwidth-to-compute crossover point shift with hardware, so a schedule tuned on one GPU class does not transfer to another. - Re-run the break-even calculation when pricing or measured throughput changes.
breakeven_extra_dollarsdepends on baseline hourly cost and the measured multiplierM. - Retain protocol metadata with every result. Model revisions, engine version, GPU, sampling parameters, prompt/output lengths, concurrency, and SLO define the measurement. The EAGLE-3 paper's reported range is not portable to a different protocol.3
How to run it in production¶
- Gate speculation with a measured batch-size schedule, using
num_speculative_tokens_per_batch_sizeto reduce or zero draft depth beyond the crossover.2 - Track cost per million accepted output tokens with acceptance, TTFT, TPOT, request goodput, and aggregate output throughput. Compare routes at the same SLO and offered load.
- Re-benchmark every target, drafter, GPU, engine, and traffic change. The practitioner regression is a warning that a supported configuration can lose, not a reusable threshold.4
Failure modes¶
| Failure mode | Cause | Mitigation |
|---|---|---|
Adequate-looking τ, net latency loss |
τ ignores drafter time; Theorem 3.8 also does not model the high-batch server. |
Measure c for low-batch screening, then A/B test the complete server. |
| Gain disappears as load rises | Verification's effective batch grows as batch_size * K and crosses the hardware-specific critical batch.2 |
Reduce or zero K above the measured crossover. |
| Published speedup fails to transfer | Model, engine, hardware, sampling, lengths, or concurrency differ.3 | Reproduce the full protocol before capacity planning. |
| Throughput gain, cost regression | Added hourly cost exceeds baseline_cost * (M - 1). |
Price measured aggregate output throughput and the complete serving allocation. |
| Dynamic schedule silently becomes static | Data parallelism is enabled; current vLLM disables the schedule to prevent collective divergence.2 | Use the documented static fallback under DP or validate a non-DP deployment. |
References¶
- Leviathan, Kalman, Matias, "Fast Inference from Transformers via Speculative Decoding," ICML 2023: https://arxiv.org/abs/2211.17192
- Li et al., "EAGLE-3: Scaling up Inference Acceleration of Large Language Models via Training-Time Test," NeurIPS 2025: https://arxiv.org/abs/2503.01840
- vLLM, Dynamic Speculative Decoding: https://docs.vllm.ai/en/latest/features/speculative_decoding/dynamic_speculative_decoding/ and
SpeculativeConfig: https://docs.vllm.ai/en/latest/api/vllm/config/speculative/ - Vizuara, "Speculative Decoding: Theory and Implementation in vLLM" (the EAGLE3-on-Llama-3.1-8B case study, cost-per-token formula, and the
τ ≳ 3practitioner heuristic): https://vizuara.substack.com/p/speculative-decoding-theory-and-implementation - Speculative decoding (accept rule, losslessness, drafter families); Evaluating speculative decoding (SPEED-Bench) (measuring
αacross domains)
Related: Speculative decoding · Evaluating speculative decoding (SPEED-Bench) · DSpark speculative decoding (DeepSeek) · Continuous batching internals · Inference serving · SLO/SLI catalog · Goodput · Glossary
-
Leviathan, Kalman, Matias, "Fast Inference from Transformers via Speculative Decoding," ICML 2023, https://arxiv.org/abs/2211.17192. Theorem 3.8 defines the stated expected walltime factor, with
cequal to draft-model run time divided by target-model run time andγsequential draft completions per round. ↩↩ -
vLLM, Dynamic Speculative Decoding, https://docs.vllm.ai/en/latest/features/speculative_decoding/dynamic_speculative_decoding/. The documentation explains the
batch_size * Kverification cost, inclusive schedule ranges,K = 0, tested methods, runner constraints, and the data-parallel fallback to staticnum_speculative_tokens. ↩↩↩↩↩↩↩ -
Li et al., "EAGLE-3," NeurIPS 2025, https://arxiv.org/abs/2503.01840. Reports 4.1x to 6.5x speedup at temperature 0 across Vicuna-13B, Llama-3.1-8B, and Llama-3.3-70B under the paper's benchmark protocol. ↩↩↩
-
Vizuara, "Speculative Decoding: Theory and Implementation in vLLM," https://vizuara.substack.com/p/speculative-decoding-theory-and-implementation. Reports an EAGLE3 deployment on Llama-3.1-8B-Instruct using a single 48 GB GPU and 500 ShareGPT prompts. It reports acceptance length
τ = 1.81, about 45 tok/s for the target in its single-stream test, and a result slower than the no-speculation baseline. This practitioner benchmark is neither independently reproduced nor peer reviewed. ↩↩↩