<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Warmup on lo0 — Tech Blog</title><link>https://blog.lo0.es/en/tags/warmup/</link><description>Recent content in Warmup on lo0 — Tech Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Tue, 16 Jun 2026 07:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/en/tags/warmup/index.xml" rel="self" type="application/rss+xml"/><item><title>Measurement bias and reproducibility: why two benchmarks of the same model give figures that differ by up to 7×</title><link>https://blog.lo0.es/en/posts/measurement-bias-reproducibility-llm-benchmarks/</link><pubDate>Tue, 16 Jun 2026 07:00:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/measurement-bias-reproducibility-llm-benchmarks/</guid><description>&lt;blockquote>
&lt;p>Notation: amounts in &lt;strong>euros (N €)&lt;/strong>, decimals with a point. The mathematical symbol is
reserved for formulas: amounts are expressed in € or USD. Thousands with a thin space
(\(1\,000\)).&lt;/p>
&lt;/blockquote>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Running the same Llama-3-70B-Instruct model on the same 4×H100 SXM 80 GB node with two
different tools can produce throughput results that differ by &lt;strong>7.2×&lt;/strong> without the engine
changing a single line of code. The cause is not the engine: it is the &lt;strong>measurement method&lt;/strong>. At
1,000 QPS, a single-process asyncio client (vLLM bench, SGLang bench, genai-perf
pre-AIPerf) processed &lt;strong>75,574 tokens&lt;/strong> against the &lt;strong>545,733 tokens&lt;/strong> of a multi-process
client, both measuring the same endpoint
(&lt;a href="https://arxiv.org/abs/2605.24217">arXiv 2605.24217&lt;/a>). The bias is not random: it is
systematic, directional and reproducible. This article catalogues the sources of bias, quantifies
their magnitude and describes the minimum harness that turns a number into an auditable datum.&lt;/p>
&lt;hr>
&lt;h2 id="the-sources-of-bias-a-catalogue-with-magnitudes">The sources of bias: a catalogue with magnitudes&lt;/h2>
&lt;p>Each source of bias moves the published number in a given direction and with a
characteristic magnitude. The table below orders the sources from largest to smallest impact
observed in the literature:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Source of bias&lt;/th>
&lt;th>Direction of the bias&lt;/th>
&lt;th>Documented magnitude&lt;/th>
&lt;th>Reference&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Single-process client saturation&lt;/strong> (Python GIL, asyncio)&lt;/td>
&lt;td>understates throughput; overstates latency&lt;/td>
&lt;td>up to &lt;strong>7.2×&lt;/strong> fewer tokens processed at 1,000 QPS&lt;/td>
&lt;td>arXiv 2605.24217&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Tokenizer different from the model&amp;rsquo;s&lt;/strong> (LLMPerf uses a universal LlamaTokenizer)&lt;/td>
&lt;td>tok/s not comparable across different vocabularies&lt;/td>
&lt;td>variable; up to &lt;strong>33 %&lt;/strong> of client overhead in the TPS denominator&lt;/td>
&lt;td>NVIDIA blog (TPS = client overhead ÷ total duration)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>ignore_eos missing or inconsistent OSL&lt;/strong>&lt;/td>
&lt;td>underestimates throughput; artificially shortens the real OSL&lt;/td>
&lt;td>up to premature termination; an unrealistic fixed-length benchmark&lt;/td>
&lt;td>vLLM bench docs; NVIDIA fundamental concepts&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Unrealistic ISL/OSL distribution&lt;/strong> (fixed length instead of a realistic distribution)&lt;/td>
&lt;td>an optimistic knee that does not resemble production&lt;/td>
&lt;td>the knee shifts; prefill understated with short prompts&lt;/td>
&lt;td>AIPerf sequence-length-distributions docs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Missing warmup / warm prefix cache&lt;/strong>&lt;/td>
&lt;td>overstates TTFT (artificially low on the first requests)&lt;/td>
&lt;td>TTFT underestimated by an already populated KV cache&lt;/td>
&lt;td>vLLM prefix caching docs; arXiv 2605.24217&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>concurrency&lt;/code> vs &lt;code>request-rate&lt;/code>&lt;/strong> as the load mode&lt;/td>
&lt;td>concurrency saturates symmetrically; request-rate can build a queue&lt;/td>
&lt;td>ITL overestimated if the queue grows without a ceiling with request-rate&lt;/td>
&lt;td>NVIDIA fundamentals; AIPerf docs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Measurement window too short&lt;/strong>&lt;/td>
&lt;td>does not capture the steady state; includes ramp-up&lt;/td>
&lt;td>throughput overestimated; latency underestimated&lt;/td>
&lt;td>meta-metrics arXiv 2508.10251&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Thermal state and GPU clocks&lt;/strong>&lt;/td>
&lt;td>thermal throttling reduces throughput without prior stabilisation&lt;/td>
&lt;td>temperature &amp;gt; 75 °C triggers throttling; a difference of ~3 W of stable power&lt;/td>
&lt;td>arXiv 2604.09048&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Warm prefix cache between runs&lt;/strong>&lt;/td>
&lt;td>overstates TTFT; unrealistic TTFT if the cache is pre-populated from the previous run&lt;/td>
&lt;td>a severe effect in multi-prompt evaluations with shared prefixes&lt;/td>
&lt;td>arXiv 2605.24217&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Mean instead of percentiles&lt;/strong>&lt;/td>
&lt;td>hides the latency tail&lt;/td>
&lt;td>P99 can be 4–6× the median at high concurrency&lt;/td>
&lt;td>NVIDIA fundamentals; Anyscale docs&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="the-dominant-bias-single-process-client-saturation">The dominant bias: single-process client saturation&lt;/h2>
&lt;p>The largest bias is not in the engine but in the &lt;strong>client that generates the load&lt;/strong>. The
single-process tools (vLLM bench, SGLang bench, genai-perf before its replacement by
AIPerf on 15 April 2026) use a single Python process with asyncio to manage the
concurrent requests. The Python Global Interpreter Lock (GIL) prevents a single process from
using more than one CPU core at a time, which introduces a bottleneck on the
client side that becomes critical at high concurrency.&lt;/p>
&lt;p>The mathematical effect: as the request rate rises, the client fails to dispatch
requests at the configured pace, accumulates queueing time on the client side, and that
time gets recorded as engine latency. The result is that TTFT and TPOT
&lt;strong>appear inflated&lt;/strong> and throughput &lt;strong>appears depressed&lt;/strong>, without the engine having changed
anything (&lt;a href="https://arxiv.org/abs/2605.24217">arXiv 2605.24217&lt;/a>).&lt;/p>
&lt;p>The documented discrepancy at 1,000 QPS:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Client architecture&lt;/th>
&lt;th>Tokens processed at 1,000 QPS&lt;/th>
&lt;th>Ratio&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Single-process (asyncio, Python GIL)&lt;/td>
&lt;td>75,574&lt;/td>
&lt;td>1× (baseline)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Multi-process (distributed load)&lt;/td>
&lt;td>545,733&lt;/td>
&lt;td>&lt;strong>7.2×&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Note: both clients point at the &lt;strong>same endpoint&lt;/strong>; the difference is entirely attributable
to the benchmark client, not to the engine.&lt;/p>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 220" role="img" aria-label="Client saturation diagram: a single-process client builds a queue on the client side and reports inflated latency; a multi-process client removes the bottleneck and measures the real engine" xmlns="http://www.w3.org/2000/svg">
&lt;style>.bx{fill:none;stroke:currentColor;stroke-width:1.3}.dsh{fill:none;stroke:currentColor;stroke-width:1.3;stroke-dasharray:5 3}.tl{font:600 12px sans-serif;fill:currentColor}.ts{font:11px sans-serif;fill:currentColor}.ar{fill:none;stroke:currentColor;stroke-width:1.3;marker-end:url(#bm2)}&lt;/style>
&lt;defs>&lt;marker id="bm2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="currentColor"/>&lt;/marker>&lt;/defs>
&lt;text x="20" y="22" class="tl">SINGLE-PROCESS (vLLM bench, SGLang bench, genai-perf pre-AIPerf)&lt;/text>
&lt;rect class="bx" x="20" y="32" width="140" height="44" rx="5"/>
&lt;text x="30" y="52" class="ts">1 Python proc.&lt;/text>
&lt;text x="30" y="67" class="ts">asyncio + GIL&lt;/text>
&lt;rect class="dsh" x="200" y="32" width="130" height="44" rx="5"/>
&lt;text x="210" y="52" class="ts">client queue&lt;/text>
&lt;text x="210" y="67" class="ts">(≠ engine queue)&lt;/text>
&lt;path class="ar" d="M160,54 L198,54"/>
&lt;path class="ar" d="M330,54 L375,54"/>
&lt;rect class="bx" x="375" y="32" width="110" height="44" rx="5"/>
&lt;text x="385" y="58" class="ts">Engine (vLLM…)&lt;/text>
&lt;text x="498" y="48" class="ts">TTFT/TPOT&lt;/text>
&lt;text x="498" y="63" class="ts">overestimated&lt;/text>
&lt;text x="498" y="78" class="ts">TPS underestimated&lt;/text>
&lt;text x="20" y="112" class="tl">MULTI-PROCESS (AIPerf, GuideLLM)&lt;/text>
&lt;rect class="bx" x="20" y="122" width="140" height="44" rx="5"/>
&lt;text x="30" y="142" class="ts">N processes&lt;/text>
&lt;text x="30" y="157" class="ts">no shared GIL&lt;/text>
&lt;path class="ar" d="M160,144 L375,144"/>
&lt;rect class="bx" x="375" y="122" width="110" height="44" rx="5"/>
&lt;text x="385" y="148" class="ts">Engine (vLLM…)&lt;/text>
&lt;text x="498" y="138" class="ts">measures the engine;&lt;/text>
&lt;text x="498" y="153" class="ts">7.2× more throughput&lt;/text>
&lt;text x="498" y="168" class="ts">captured&lt;/text>
&lt;text x="20" y="210" class="ts">The client architecture determines what gets measured: the client bottleneck or the engine's.&lt;/text>
&lt;/svg>
&lt;/div>
&lt;hr>
&lt;h2 id="tokenizer-bias-toks-are-not-comparable-across-vocabularies">Tokenizer bias: tok/s are not comparable across vocabularies&lt;/h2>
&lt;p>Tokens are not universal. Each model has its own tokenizer with its own
vocabulary. Llama-3 uses a vocabulary of 128,256 tokens; Gemma uses 256,128; earlier
models used 32,000–50,000. The same English text produces a different number of tokens
depending on the model&amp;rsquo;s tokenizer.&lt;/p>
&lt;p>The direct consequence for benchmarking: if the tool measures tok/s with a
tokenizer different from that of the model being served, the token count, and therefore the throughput in
tok/s and the cost per token, are biased. LLMPerf (archived in December 2025) used
&lt;strong>LlamaTokenizer&lt;/strong> universally for all models, which guaranteed internal consistency
in the leaderboard but made the tok/s &lt;strong>not comparable&lt;/strong> with measurements of other
models with different vocabularies.&lt;/p>
&lt;p>The TPS formula in LLMPerf additionally included the benchmark&amp;rsquo;s full denominator, the time
spent generating prompts, preparing requests and storing responses, which
NVIDIA estimated at up to &lt;strong>33 % of the total duration&lt;/strong> at concurrency 1. This makes
LLMPerf&amp;rsquo;s TPS systematically lower than that of GenAI-Perf/AIPerf for the same system,
without the engine being worse:&lt;/p>
$$\text{TPS}_{\text{LLMPerf}} = \frac{\text{output tokens}}{T_{\text{end}} - T_{\text{start}}}$$
$$\text{TPS}_{\text{GenAI-Perf}} = \frac{\text{output tokens}}{T_y - T_x}$$
&lt;p>Where \(T_{\text{start}}\) and \(T_{\text{end}}\) include the client overheads, while
\(T_x\) and \(T_y\) are the instant of the first request and that of the last token received,
respectively (&lt;a href="https://developer.nvidia.com/blog/llm-benchmarking-fundamental-concepts/">NVIDIA · Fundamental Concepts&lt;/a>).&lt;/p>
&lt;p>The operational rule: &lt;strong>always count tokens with the tokenizer of the model being served&lt;/strong>, not with a
proxy tokenizer.&lt;/p>
&lt;hr>
&lt;h2 id="the-bias-of-ignore_eos-and-an-inconsistent-osl">The bias of ignore_eos and an inconsistent OSL&lt;/h2>
&lt;p>Most LLM models generate a special end-of-sequence token (EOS) when
they consider the response complete. If the benchmark does not set &lt;code>ignore_eos=True&lt;/code>, the real
output length (OSL) varies from request to request according to the model&amp;rsquo;s natural length
distribution, which produces:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Inconsistent OSL&lt;/strong>: two runs with the same seed can produce different OSL
distributions if the model varies its natural output.&lt;/li>
&lt;li>&lt;strong>Spurious comparison&lt;/strong>: a &amp;ldquo;faster&amp;rdquo; model may be so simply because it generates
shorter responses (it hits EOS sooner), not because it has more real throughput.&lt;/li>
&lt;li>&lt;strong>Underestimated throughput&lt;/strong>: if the benchmark expects OSL=256 but the model stops at
OSL=80 on average, the throughput in tok/s appears higher but measures less work.&lt;/li>
&lt;/ol>
&lt;p>The &lt;code>ignore_eos&lt;/code> parameter (or &lt;code>--ignore-eos&lt;/code> in vLLM bench) instructs the engine to ignore the
EOS token and continue until reaching &lt;code>max_tokens&lt;/code>. It is &lt;strong>mandatory&lt;/strong> for the OSL to be the
configured one rather than the model&amp;rsquo;s natural one, and for two runs to be comparable
(&lt;a href="https://docs.vllm.ai/en/latest/benchmarking/cli/">vLLM benchmark CLI docs&lt;/a>).&lt;/p>
&lt;hr>
&lt;h2 id="the-bias-of-the-islosl-distribution">The bias of the ISL/OSL distribution&lt;/h2>
&lt;p>The distribution of input (ISL) and output (OSL) lengths determines what proportion of the
compute time goes to prefill (costly in TTFT) and how much to decode (costly in
ITL). A benchmark with a fixed length, say ISL=128, OSL=128, produces results that
do not resemble any real traffic.&lt;/p>
&lt;p>Real use cases have very different distributions:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Use case&lt;/th>
&lt;th>Typical ISL (tokens)&lt;/th>
&lt;th>Typical OSL (tokens)&lt;/th>
&lt;th>Dominated by&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Translation&lt;/td>
&lt;td>500–2,000&lt;/td>
&lt;td>500–2,000&lt;/td>
&lt;td>balanced&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Generation (code, email)&lt;/td>
&lt;td>~100&lt;/td>
&lt;td>~1,000&lt;/td>
&lt;td>decode (long OSL)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Summarisation / RAG&lt;/td>
&lt;td>~1,000&lt;/td>
&lt;td>~100&lt;/td>
&lt;td>prefill (long ISL)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Reasoning (CoT)&lt;/td>
&lt;td>~100&lt;/td>
&lt;td>1,000–10,000&lt;/td>
&lt;td>very long decode&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>A short-ISL benchmark with a model optimised for prefill will give an artificially
low TTFT and an artificially high throughput. The knee of the sweep shifts: with ISL=64 the
system admits more concurrency without breaking the TTFT SLO; with ISL=1,024 prefill saturates
earlier and the knee appears earlier. Using the wrong distribution means sizing for traffic
that does not exist.&lt;/p>
&lt;p>AIPerf introduces &lt;strong>sequence distributions&lt;/strong> with configurable per-component variance
to reproduce realistic traffic mixes
(&lt;a href="https://docs.nvidia.com/aiperf/tutorials/datasets-inputs/sequence-length-distributions-for-advanced-benchmarking">AIPerf · Sequence Length Distributions&lt;/a>):&lt;/p>
&lt;pre tabindex="0">&lt;code>--sequence-distribution &amp;#34;64|10,32|8:70;256|40,128|20:20;1024|100,512|50:10&amp;#34;
&lt;/code>&lt;/pre>&lt;p>This creates 70 % of requests with \(\text{ISL} \sim \mathcal{N}(64, 10)\) and
\(\text{OSL} \sim \mathcal{N}(32, 8)\), 20 % with medium ISL/OSL, and 10 % with
long ISL/OSL, far more faithful to real chatbot traffic than a fixed length.&lt;/p>
&lt;hr>
&lt;h2 id="the-bias-of-warmup-and-the-prefix-cache">The bias of warmup and the prefix cache&lt;/h2>
&lt;p>Two related but distinct sources of bias:&lt;/p>
&lt;p>&lt;strong>Missing warmup.&lt;/strong> The first requests of a benchmark hit a &amp;ldquo;cold&amp;rdquo; engine: the
GPU is in a low-clock state, the KV cache is empty, and the operating system may
be paging memory. The TTFT of the first requests is structurally higher than
that of the steady state. If the benchmark does not discard a warmup period, the mean
TTFT includes these outliers and overestimates the real production latency. Some frameworks
(GenAI-Perf/AIPerf) use a &lt;strong>sliding window&lt;/strong> that excludes the ramp-up and
ramp-down requests; others do not.&lt;/p>
&lt;p>&lt;strong>Warm prefix cache between runs.&lt;/strong> The prefix KV cache (prefix cache or prompt
cache) stores the computed results of repeated prompt prefixes. If the
benchmark runs multiple consecutive runs with the same prompts, the second and
subsequent runs find the KV cache already populated and report an artificially
low TTFT, that of the decode, not of the prefill. For a baseline benchmark, the prefix cache must
be cold; for one that simulates production with repeated prompts, warm. The distinction
must be made explicit
(&lt;a href="https://arxiv.org/abs/2605.24217">arXiv 2605.24217&lt;/a>; &lt;a href="https://docs.vllm.ai/en/stable/design/prefix_caching/">vLLM · Automatic Prefix Caching&lt;/a>).&lt;/p>
&lt;hr>
&lt;h2 id="the-bias-of-concurrency-vs-request-rate">The bias of &lt;code>concurrency&lt;/code> vs &lt;code>request-rate&lt;/code>&lt;/h2>
&lt;p>The two load control modes produce different latency distributions for the
same system:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Mode&lt;/th>
&lt;th>Semantics&lt;/th>
&lt;th>When to use&lt;/th>
&lt;th>Risk&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>concurrency N&lt;/strong>&lt;/td>
&lt;td>keeps exactly N requests in flight; as soon as one finishes, it launches another&lt;/td>
&lt;td>measuring the system under a fixed concurrency load&lt;/td>
&lt;td>over-represents sustained load; does not simulate real arrivals&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>request-rate r&lt;/strong> (constant or Poisson)&lt;/td>
&lt;td>launches one request every \(1/r\) seconds (constant) or with interarrival \(\sim \text{Exp}(1/r)\) (Poisson)&lt;/td>
&lt;td>simulating real traffic (random arrivals)&lt;/td>
&lt;td>if the engine cannot absorb r req/s, the queue grows without a ceiling&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>NVIDIA recommends the &lt;strong>concurrency&lt;/strong> mode for most capacity benchmarks
(&lt;a href="https://developer.nvidia.com/blog/llm-benchmarking-fundamental-concepts/">NVIDIA · LLM Benchmarking Fundamental Concepts&lt;/a>). The request-rate mode is more faithful for online traffic
(a Poisson distribution of arrivals), but if the rate exceeds the engine&amp;rsquo;s capacity the queue
grows indefinitely and the latency metrics include queueing time that can
dominate the TTFT, mixing queue behaviour with engine behaviour.&lt;/p>
&lt;p>A system measured at concurrency=16 and another at request-rate=16 req/s &lt;strong>are not under the
same load&lt;/strong>: fixed concurrency guarantees 16 simultaneous requests; the rate sets
the arrival pace but not the instantaneous concurrency. Comparing their results without adjustment
is incorrect.&lt;/p>
&lt;hr>
&lt;h2 id="the-bias-of-the-measurement-window-and-the-thermal-state">The bias of the measurement window and the thermal state&lt;/h2>
&lt;p>&lt;strong>Window too short.&lt;/strong> A 30-second benchmark may measure the system&amp;rsquo;s
ramp-up, not the steady state. The recommendation of arXiv 2508.10251 is that the measurement
window cover at least 3-5× the system&amp;rsquo;s ramp time under load, and that the
metrics be computed only over the steady window, excluding warmup and cooldown.&lt;/p>
&lt;p>&lt;strong>Thermal state of the GPU.&lt;/strong> Datacenter GPUs (H100 SXM, A100) operate with thermal
throttling above ~75 °C. If the GPU has not reached its steady-state temperature before the
benchmark, the first measurements correspond to a higher-clock state than the
sustainable one. Controlled experiments document that power must stabilise within a
range of &lt;strong>3 W&lt;/strong> for at least 30 seconds before the measurements are representative
(&lt;a href="https://arxiv.org/html/2604.09048v1">arXiv 2604.09048 · Watt Counts&lt;/a>). The effect is
especially severe in prefill benchmarks (TTFT), where the high clocks of the cold
state produce an artificially low TTFT.&lt;/p>
&lt;p>For a reproducible benchmark on 4×H100 SXM 80 GB: before measuring, run sustained load
for at least 2–3 minutes until &lt;code>nvidia-smi&lt;/code> reports a stable temperature and stable
power (variation &amp;lt; 3 W over 30 s). Only then start the measurement window.&lt;/p>
&lt;hr>
&lt;h2 id="how-the-tools-compute-itl-differently">How the tools compute ITL differently&lt;/h2>
&lt;p>ITL (Inter-Token Latency) appears in every tool but its formula varies, and the
differences are not small:&lt;/p>
&lt;p>&lt;strong>GenAI-Perf / AIPerf:&lt;/strong>&lt;/p>
$$\text{ITL} = \frac{\text{e2e latency} - \text{TTFT}}{\text{output tokens} - 1}$$
&lt;p>TTFT is excluded from the numerator and the denominator discounts the first token. ITL is a
pure &lt;strong>decode&lt;/strong> metric, with no prefill contamination.&lt;/p>
&lt;p>&lt;strong>LLMPerf&lt;/strong> (archived Dec. 2025):&lt;/p>
$$\text{ITL}_{\text{LLMPerf}} = \frac{\text{e2e latency}}{\text{output tokens}}$$
&lt;p>TTFT &lt;strong>is included&lt;/strong> in the numerator. For short sequences (OSL &amp;lt; 50 tokens), TTFT
can represent 50–80 % of the e2e_latency, so that LLMPerf&amp;rsquo;s ITL measures
mainly prefill, not decode. Two systems with the same decode but different
prefill will show different ITLs in LLMPerf even if they are identical in decode speed.&lt;/p>
&lt;p>&lt;strong>vLLM bench (benchmark_serving.py):&lt;/strong>&lt;/p>
&lt;p>It computes ITL as the mean of the intervals between consecutive tokens of the output stream,
including intra-request variance. It can reveal decode jitter that the others average away.&lt;/p>
&lt;p>The practical consequence: &lt;strong>never cross a GenAI-Perf ITL with an LLMPerf one&lt;/strong> as if
they were the same metric. They are different formulas over the same signal.&lt;/p>
&lt;hr>
&lt;h2 id="comparability-across-tools-why-their-numbers-do-not-cross">Comparability across tools: why their numbers do not cross&lt;/h2>
&lt;p>The following table summarises the methodological differences that make one tool&amp;rsquo;s numbers
&lt;strong>structurally incompatible&lt;/strong> with another&amp;rsquo;s without an explicit adjustment:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Dimension&lt;/th>
&lt;th>vLLM bench&lt;/th>
&lt;th>LLMPerf (archived)&lt;/th>
&lt;th>GenAI-Perf / AIPerf&lt;/th>
&lt;th>GuideLLM&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Client architecture&lt;/strong>&lt;/td>
&lt;td>single-process asyncio&lt;/td>
&lt;td>single-process&lt;/td>
&lt;td>&lt;strong>multi-process&lt;/strong>&lt;/td>
&lt;td>&lt;strong>multi-process&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>ITL includes TTFT&lt;/strong>&lt;/td>
&lt;td>no&lt;/td>
&lt;td>&lt;strong>yes&lt;/strong>&lt;/td>
&lt;td>no&lt;/td>
&lt;td>no&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>TPS denominator&lt;/strong>&lt;/td>
&lt;td>\(T_y - T_x\)&lt;/td>
&lt;td>\(T_{\text{end}} - T_{\text{start}}\) (overhead included)&lt;/td>
&lt;td>\(T_y - T_x\)&lt;/td>
&lt;td>per round&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Tokenizer&lt;/strong>&lt;/td>
&lt;td>that of the model served&lt;/td>
&lt;td>universal LlamaTokenizer&lt;/td>
&lt;td>that of the model served&lt;/td>
&lt;td>that of the model served&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Warmup / sliding window&lt;/strong>&lt;/td>
&lt;td>not automatic&lt;/td>
&lt;td>no&lt;/td>
&lt;td>&lt;strong>yes (sliding window)&lt;/strong>&lt;/td>
&lt;td>per round&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>ignore_eos by default&lt;/strong>&lt;/td>
&lt;td>no&lt;/td>
&lt;td>no&lt;/td>
&lt;td>explicitly recommended&lt;/td>
&lt;td>configurable&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>ISL/OSL distribution&lt;/strong>&lt;/td>
&lt;td>manual parameter&lt;/td>
&lt;td>manual parameter&lt;/td>
&lt;td>distributions with variance&lt;/td>
&lt;td>configurable &lt;code>--data&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Primary load mode&lt;/strong>&lt;/td>
&lt;td>concurrency&lt;/td>
&lt;td>concurrency (drained batches)&lt;/td>
&lt;td>concurrency (recommended)&lt;/td>
&lt;td>sweep + poisson&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Structured output&lt;/strong>&lt;/td>
&lt;td>basic JSON&lt;/td>
&lt;td>JSON&lt;/td>
&lt;td>JSON + CSV&lt;/td>
&lt;td>JSON + HTML + CSV&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>An LLMPerf result and a GenAI-Perf result for the same endpoint can differ in TTFT,
ITL and TPS &lt;strong>simultaneously&lt;/strong> and in all of them for methodological reasons, not because of engine
differences. The only way to cross them is to run both tools on the same system
under the same conditions and compute the empirical conversion factor, which in practice
amounts to re-measuring with a single tool.&lt;/p>
&lt;hr>
&lt;h2 id="the-honest-harness-a-reproducibility-checklist">The honest harness: a reproducibility checklist&lt;/h2>
&lt;p>A benchmark whose number can be defended in an audit has to come accompanied by
all the metadata that allow it to be reproduced. The minimum to demand, organised by category:&lt;/p>
&lt;h3 id="hardware">Hardware&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Metadata&lt;/th>
&lt;th>Example 4×H100&lt;/th>
&lt;th>Effect if not fixed&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>GPU (model, variant, count)&lt;/td>
&lt;td>4× NVIDIA H100 SXM 80 GB&lt;/td>
&lt;td>H100 PCIe vs SXM differ in memory BW and NVLink&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>GPU-GPU interconnect&lt;/td>
&lt;td>NVLink 4.0&lt;/td>
&lt;td>tensor parallelism depends on the interconnect BW&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CPU, RAM, CPU-GPU bandwidth&lt;/td>
&lt;td>2× Intel Xeon 8480+, 512 GB DDR5, PCIe 5.0&lt;/td>
&lt;td>the tokenisation bottleneck can be on the CPU&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Thermal state at the start&lt;/td>
&lt;td>GPU temperature &amp;lt; 65 °C, stable power ± 3 W&lt;/td>
&lt;td>throttling alters TPS and TTFT by up to ~15 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>GPU clocks&lt;/td>
&lt;td>without &lt;code>nvidia-smi -pm 1&lt;/code> they can vary&lt;/td>
&lt;td>a difference of up to ~10 % in throughput&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="software-and-model">Software and model&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Metadata&lt;/th>
&lt;th>Example&lt;/th>
&lt;th>Effect if not fixed&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Engine + version + flags&lt;/td>
&lt;td>vLLM 0.8.4, &lt;code>--tensor-parallel-size 4 --gpu-memory-utilization 0.90&lt;/code>&lt;/td>
&lt;td>each version changes the scheduler and the KV cache management&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Model + precision&lt;/td>
&lt;td>Llama-3-70B-Instruct, FP8&lt;/td>
&lt;td>FP16 vs FP8 differ by ~1.4–1.8× in throughput&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Tokenizer used for counting&lt;/td>
&lt;td>tokenizer of the model served (HF tokenizer)&lt;/td>
&lt;td>a universal LlamaTokenizer biases tok/s across vocabularies&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Generation seed&lt;/td>
&lt;td>&lt;code>--seed 42&lt;/code>&lt;/td>
&lt;td>without a fixed seed, the OSL varies run-to-run&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>ignore_eos&lt;/code>&lt;/td>
&lt;td>&lt;code>True&lt;/code>&lt;/td>
&lt;td>without it, the OSL varies with the prompt content&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Sampling parameters&lt;/td>
&lt;td>&lt;code>temperature=1.0, top_p=0.95&lt;/code>&lt;/td>
&lt;td>greedy vs sampling affect logit speed&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="load">Load&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Metadata&lt;/th>
&lt;th>Example&lt;/th>
&lt;th>Effect if not fixed&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Bench tool + version&lt;/td>
&lt;td>AIPerf 0.2.1&lt;/td>
&lt;td>each version changes formulas and warmup&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ISL/OSL distribution&lt;/td>
&lt;td>\(\mathcal{N}(512, 64)\) ISL, \(\mathcal{N}(128, 20)\) OSL&lt;/td>
&lt;td>changing the distribution moves the knee&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Load mode&lt;/td>
&lt;td>concurrency, sweep 1–64&lt;/td>
&lt;td>concurrency vs request-rate: different distributions&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Concurrency levels&lt;/td>
&lt;td>1, 2, 4, 8, 16, 32, 64 (full sweep, beyond the knee)&lt;/td>
&lt;td>without passing the knee, the safe capacity is unknown&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Duration per point&lt;/td>
&lt;td>120 s minimum per level&lt;/td>
&lt;td>short windows capture ramp-up, not the steady state&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Warmup&lt;/td>
&lt;td>30 s excluded from the metric computation&lt;/td>
&lt;td>without warmup, the metrics include the cold state&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Prefix cache treatment&lt;/td>
&lt;td>cold (flush between runs) or warm (declared explicitly)&lt;/td>
&lt;td>warm cache: unrealistic TTFT for a baseline&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="slo-and-reported-metrics">SLO and reported metrics&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Metadata&lt;/th>
&lt;th>Example&lt;/th>
&lt;th>Effect if not declared&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Declared SLO&lt;/td>
&lt;td>TTFT P99 &amp;lt; 500 ms, ITL P95 &amp;lt; 50 ms&lt;/td>
&lt;td>goodput depends on the SLO; without an SLO there is no goodput&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Reported percentiles&lt;/td>
&lt;td>P50, P95, P99 (not just the mean)&lt;/td>
&lt;td>the mean hides the tail; irrelevant for an SLO&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Throughput vs goodput&lt;/td>
&lt;td>goodput under the SLO, not raw throughput&lt;/td>
&lt;td>catalogue throughput can be 5–10× the goodput&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Total number of requests&lt;/td>
&lt;td>≥ 1,000 per concurrency level&lt;/td>
&lt;td>small samples: high variance in percentiles&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="methodological-defence-of-the-datum-before-an-audit">Methodological defence of the datum before an audit&lt;/h2>
&lt;p>A throughput number presented without the data sheet above is not a datum: it is an anecdote.
The validation pattern for a technical audit:&lt;/p>
&lt;p>&lt;strong>1. Traceability of the tool.&lt;/strong> The tool and its version must be pinnable to a
Git commit or a container image hash. AIPerf and GuideLLM export JSON with
version metadata; vLLM bench omits them by default and they have to be captured manually.&lt;/p>
&lt;p>&lt;strong>2. Reproducibility of the environment.&lt;/strong> The engine deployment script (or the Kubernetes
manifest) and the exact benchmark command must be enough for a third party to
reproduce the number on the same hardware. GuideLLM exports the benchmark file as an
authoritative record of the session: configuration, metadata, per-benchmark statistics and
request entries with individual timings
(&lt;a href="https://github.com/vllm-project/guidellm">GitHub vllm-project/guidellm&lt;/a>).&lt;/p>
&lt;p>&lt;strong>3. Verification of the steady state.&lt;/strong> The metrics must come from the benchmark&amp;rsquo;s
steady window (warmup excluded). The throughput vs concurrency curve must
show the knee, the point where throughput saturates and latency blows up, and extend
beyond it. Without a visible knee, the reported capacity may be the client&amp;rsquo;s limit, not
the engine&amp;rsquo;s.&lt;/p>
&lt;p>&lt;strong>4. Goodput, not raw throughput.&lt;/strong> The auditable throughput is the goodput under the declared
SLO, not the peak throughput. A system that reports 4,000 tok/s but whose goodput
under TTFT P99 &amp;lt; 500 ms is 1,800 tok/s has a real capacity of 1,800 tok/s for
interactive use cases.&lt;/p>
&lt;p>&lt;strong>5. Internal comparability.&lt;/strong> If two engines or two configurations are compared, the
tool, the load distribution, the SLO, the hardware and the warmup treatment
must be &lt;strong>identical&lt;/strong>. Any difference in these dimensions contaminates the comparison.&lt;/p>
&lt;p>The goodput formula as an auditable metric:&lt;/p>
$$\text{goodput} = \text{throughput} \times \Pr[\text{TTFT} \leq \text{SLO}_{\text{TTFT}}] \times \Pr[\text{ITL} \leq \text{SLO}_{\text{ITL}}]$$
&lt;p>Where the probabilities are estimated over the empirical distribution of the run. An engine
with a throughput of 4,000 tok/s and \(\Pr[\text{TTFT} \leq 500\,\text{ms}] = 0.45\) has
a goodput of \(4{,}000 \times 0.45 = 1{,}800\) tok/s.&lt;/p>
&lt;hr>
&lt;h2 id="a-numerical-example-the-same-node-four-different-measurements">A numerical example: the same node, four different measurements&lt;/h2>
&lt;p>Reference hardware: 4×H100 SXM 80 GB, model Llama-3-70B-Instruct FP8, tensor
parallel 4, SLO TTFT P99 &amp;lt; 500 ms.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Benchmark configuration&lt;/th>
&lt;th>Reported throughput&lt;/th>
&lt;th>Real goodput&lt;/th>
&lt;th>Factor vs goodput&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>vLLM bench, concurrency=32, no ignore_eos, no warmup, fixed OSL=64&lt;/td>
&lt;td>5,800 tok/s&lt;/td>
&lt;td>~1,200 tok/s (short OSL inflates TPS)&lt;/td>
&lt;td>&lt;strong>4.8×&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>LLMPerf, concurrency=32, LlamaTokenizer, overhead included in the denominator&lt;/td>
&lt;td>3,100 tok/s&lt;/td>
&lt;td>~1,600 tok/s (ITL includes TTFT)&lt;/td>
&lt;td>&lt;strong>1.9×&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>AIPerf, concurrency=32, ignore_eos, sliding window, model&amp;rsquo;s tokenizer&lt;/td>
&lt;td>3,400 tok/s&lt;/td>
&lt;td>3,350 tok/s&lt;/td>
&lt;td>&lt;strong>1.01×&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>GuideLLM, sweep 1–64, poisson, realistic ISL/OSL distribution, declared SLO&lt;/td>
&lt;td>3,330 tok/s goodput (knee at round 6)&lt;/td>
&lt;td>3,330 tok/s&lt;/td>
&lt;td>&lt;strong>1.0× (honest baseline)&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The range: from 1,200 tok/s to 5,800 tok/s for the same engine, the same hardware and the same
model. The maximum factor is &lt;strong>4.8×&lt;/strong>. The cause is not the engine; it is the
instrumentation decisions.&lt;/p>
&lt;hr>
&lt;h2 id="decomposing-the-total-bias">Decomposing the total bias&lt;/h2>
&lt;p>The total observable bias between two tools is the multiplicative composition of the
individual biases. For a comparison of single-process vLLM bench vs multi-process GuideLLM
on the same system:&lt;/p>
$$\text{total factor} \approx \underbrace{f_{\text{client}}}_{\leq 7.2\times} \times \underbrace{f_{\text{tokenizer}}}_{1.0{-}1.3\times} \times \underbrace{f_{\text{ignore-eos}}}_{1.0{-}2.0\times} \times \underbrace{f_{\text{ISL/OSL}}}_{1.0{-}1.5\times} \times \underbrace{f_{\text{warmup}}}_{1.0{-}1.2\times}$$
&lt;p>The client saturation factor (\(\leq 7.2\times\)) dominates, but the other factors
multiply. Under adverse conditions (single-process client + different tokenizer + no
ignore_eos + unrealistic OSL + no warmup), the compound bias can exceed &lt;strong>15–20×&lt;/strong> for
the same system.&lt;/p>
&lt;hr>
&lt;h2 id="state-of-the-art-2026-what-has-changed">State of the art 2026: what has changed&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>genai-perf → AIPerf migration&lt;/strong> (15 Apr 2026): NVIDIA retired genai-perf and replaced it
with AIPerf, which is multi-process with automatic saturation detection, configurable
ISL/OSL distributions and a built-in sliding window. The migration removes the single-process
client bias from NVIDIA&amp;rsquo;s official tooling.&lt;/li>
&lt;li>&lt;strong>LLMPerf archived&lt;/strong> (Dec. 2025): the &lt;code>ray-project/llmperf&lt;/code> repository is archived and
in read-only mode. The historical results of the LLMPerf leaderboard are comparable
only among themselves; they must not be crossed with modern measurements without adjustment.&lt;/li>
&lt;li>&lt;strong>GuideLLM 0.5.x&lt;/strong> (2025–2026): a complete architectural refactor, multimodal support, and
authoritative JSON export with all the session metadata. It is the OSS standard for
SLO-driven evaluation.&lt;/li>
&lt;li>&lt;strong>arXiv 2605.24217&lt;/strong> (May 2026): the first formal characterisation of systematic measurement
bias in production LLM benchmarks, with a mathematical demonstration of the GIL effect and
a proposal for a multi-process harness.&lt;/li>
&lt;li>&lt;strong>arXiv 2508.10251&lt;/strong>: meta-metrics and good practice for system-level performance
benchmarking; it establishes the minimum dimensions of the parameter space that must be
declared for a result to be reproducible.&lt;/li>
&lt;li>&lt;strong>MLPerf Inference v5.1&lt;/strong> (Sep. 2025): 27 participants, a participation record. The
MLPerf rules require declaring the exact code, the dataset and the hardware, and admit
public review; it is the only industry benchmark with a formal review process for
reproducibility.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="cross-links-from-the-benchmarking-track">Cross-links from the benchmarking track&lt;/h2>
&lt;p>The biases described here apply to every tool in the catalogue. For the complete
data sheet of each tool:&lt;/p>
&lt;ul>
&lt;li>Full catalogue: &lt;a href="https://blog.lo0.es/en/posts/llm-benchmark-tool-catalogue-practical-deep-dive/">LLM benchmarking tools, data sheet by data sheet&lt;/a>&lt;/li>
&lt;li>GuideLLM and SLO validation: &lt;a href="https://blog.lo0.es/en/posts/guidellm-validating-slo-under-load-sizing-knee/">GuideLLM in depth: validating the SLO under load&lt;/a>&lt;/li>
&lt;li>AIPerf (ex genai-perf) and saturation detection: &lt;a href="https://blog.lo0.es/en/posts/genai-perf-llm-inference-profiling-in-depth/">NVIDIA GenAI-Perf in depth&lt;/a>&lt;/li>
&lt;li>State of the art of frameworks: &lt;a href="https://blog.lo0.es/en/posts/llm-inference-benchmarking-frameworks-metrics-state-of-the-art/">LLM benchmarking: frameworks and state of the art&lt;/a>&lt;/li>
&lt;li>Engine decision on the Pareto axis: &lt;a href="https://blog.lo0.es/en/posts/llm-serving-engines-pareto-frontier-comparison/">Serving engines compared: the Pareto frontier&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="sources">Sources&lt;/h2>
&lt;ul>
&lt;li>arXiv 2605.24217 · Identifying and Mitigating Systemic Measurement Bias in Production LLM Inference Benchmarks — &lt;a href="https://arxiv.org/abs/2605.24217">https://arxiv.org/abs/2605.24217&lt;/a>&lt;/li>
&lt;li>arXiv 2508.10251 · Meta-Metrics and Best Practices for System-Level Inference Performance Benchmarking — &lt;a href="https://arxiv.org/pdf/2508.10251">https://arxiv.org/pdf/2508.10251&lt;/a>&lt;/li>
&lt;li>arXiv 2604.09048 · Watt Counts: Energy-Aware Benchmark for Sustainable LLM Inference on Heterogeneous GPU Architectures — &lt;a href="https://arxiv.org/html/2604.09048v1">https://arxiv.org/html/2604.09048v1&lt;/a>&lt;/li>
&lt;li>NVIDIA Technical Blog · LLM Inference Benchmarking: Fundamental Concepts (ITL, TPS, ISL/OSL, ignore_eos, concurrency vs request-rate) — &lt;a href="https://developer.nvidia.com/blog/llm-benchmarking-fundamental-concepts/">https://developer.nvidia.com/blog/llm-benchmarking-fundamental-concepts/&lt;/a>&lt;/li>
&lt;li>NVIDIA AIPerf Docs · Sequence Length Distributions for Advanced Benchmarking — &lt;a href="https://docs.nvidia.com/aiperf/tutorials/datasets-inputs/sequence-length-distributions-for-advanced-benchmarking">https://docs.nvidia.com/aiperf/tutorials/datasets-inputs/sequence-length-distributions-for-advanced-benchmarking&lt;/a>&lt;/li>
&lt;li>NVIDIA AIPerf · Request Rate with Max Concurrency — &lt;a href="https://docs.nvidia.com/aiperf/tutorials/load-patterns-scheduling/request-rate-with-max-concurrency">https://docs.nvidia.com/aiperf/tutorials/load-patterns-scheduling/request-rate-with-max-concurrency&lt;/a>&lt;/li>
&lt;li>NVIDIA AIPerf · Comprehensive LLM Benchmarking Guide — &lt;a href="https://lucaberton.com/blog/nvidia-aiperf-llm-inference-benchmarking-guide/">https://lucaberton.com/blog/nvidia-aiperf-llm-inference-benchmarking-guide/&lt;/a>&lt;/li>
&lt;li>vLLM Documentation · Benchmark CLI (ignore_eos, métricas disponibles) — &lt;a href="https://docs.vllm.ai/en/latest/benchmarking/cli/">https://docs.vllm.ai/en/latest/benchmarking/cli/&lt;/a>&lt;/li>
&lt;li>vLLM Documentation · Automatic Prefix Caching — &lt;a href="https://docs.vllm.ai/en/stable/design/prefix_caching/">https://docs.vllm.ai/en/stable/design/prefix_caching/&lt;/a>&lt;/li>
&lt;li>GitHub · ray-project/llmperf (archivado dic. 2025) — &lt;a href="https://github.com/ray-project/llmperf">https://github.com/ray-project/llmperf&lt;/a>&lt;/li>
&lt;li>GitHub · vllm-project/guidellm (exportación JSON autoritativa, metadatos de sesión) — &lt;a href="https://github.com/vllm-project/guidellm">https://github.com/vllm-project/guidellm&lt;/a>&lt;/li>
&lt;li>Red Hat Developer · GuideLLM: evaluar despliegues LLM para inferencia real — &lt;a href="https://developers.redhat.com/articles/2025/06/20/guidellm-evaluate-llm-deployments-real-world-inference">https://developers.redhat.com/articles/2025/06/20/guidellm-evaluate-llm-deployments-real-world-inference&lt;/a>&lt;/li>
&lt;li>MLCommons · MLPerf Inference v5.1 results (récord 27 participantes, reproducibilidad formal) — &lt;a href="https://mlcommons.org/2025/09/mlperf-inference-v5-1-results/">https://mlcommons.org/2025/09/mlperf-inference-v5-1-results/&lt;/a>&lt;/li>
&lt;li>arXiv 2502.16721 · Speed and Conversational LLMs: Not All Is About Tokens per Second (tokenizer incompatibilidad y tok/s entre vocabularios) — &lt;a href="https://arxiv.org/pdf/2502.16721">https://arxiv.org/pdf/2502.16721&lt;/a>&lt;/li>
&lt;li>Medium · LLM Inference Benchmarking (genAI-perf y vLLM, discrepancia 7,2×) — &lt;a href="https://kchandan.medium.com/llm-inference-benchmarking-genai-perf-and-vllm-5dd06b57428e">https://kchandan.medium.com/llm-inference-benchmarking-genai-perf-and-vllm-5dd06b57428e&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>