<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Tpot on lo0 — Tech Blog</title><link>https://blog.lo0.es/en/tags/tpot/</link><description>Recent content in Tpot on lo0 — Tech Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sat, 29 Aug 2026 09:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/en/tags/tpot/index.xml" rel="self" type="application/rss+xml"/><item><title>MLPerf Inference: how to read it, what LoadGen enforces and what comparability it offers</title><link>https://blog.lo0.es/en/posts/mlperf-inference-reading-loadgen-comparability/</link><pubDate>Sat, 29 Aug 2026 09:00:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/mlperf-inference-reading-loadgen-comparability/</guid><description>&lt;blockquote>
&lt;p>Notation: amounts in &lt;strong>euros (N €)&lt;/strong>, decimals with a point. The dollar sign is not used
(on this site it is a formula delimiter).&lt;/p>
&lt;/blockquote>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>MLPerf Inference is maintained by MLCommons on a six-monthly cadence. It imposes three things no home-made benchmark has: a &lt;strong>mandatory load generator&lt;/strong> (LoadGen, compiled from a tagged revision and unmodified), model-equivalence rules that bound what can be optimised, and an &lt;strong>audit process&lt;/strong> that reviews up to two submissions per round. The four scenarios (SingleStream, MultiStream, Server, Offline) have a minimum duration of 600 s and different metrics: Server reports the sustained Poisson rate and is the only one with a latency constraint. For the LLM benchmarks that constraint is not a request latency but two simultaneous SLOs at the 99th percentile: TTFT and TPOT, with per-model figures ranging from 2000 ms / 200 ms on Llama 2 70B to 450 ms / 40 ms on its Interactive variant. Quality is required relative to the reference model (99 % or 99.9 %) and the &lt;strong>generation length&lt;/strong> is audited as well (Llama 2 70B: more than 90 % of 294.45 tokens per sample). Three reading rules sum up the real comparability: results are only compared within the same version, division, category and scenario; per-accelerator is not an official MLCommons metric, it is derived; and neither cost nor energy enters the primary metric, to the point that round v5.1 had 2 power submissions against 27 participating organisations.&lt;/p>
&lt;hr>
&lt;h2 id="what-it-is-and-how-it-is-organised">What it is and how it is organised&lt;/h2>
&lt;p>MLPerf Inference is maintained by the &lt;strong>MLCommons Association&lt;/strong> through the MLPerf Inference Working Group, whose participation is limited to MLCommons members and affiliates (&lt;a href="https://mlcommons.org/working-groups/benchmarks/inference/">MLPerf Inference Working Group&lt;/a>). The declared cadence for publishing results is roughly six months.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Round&lt;/th>
&lt;th>Results published&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>v4.0&lt;/td>
&lt;td>27 March 2024&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>v4.1&lt;/td>
&lt;td>28 August 2024&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>v5.0&lt;/td>
&lt;td>2 April 2025&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>v5.1&lt;/td>
&lt;td>9 September 2025&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>v6.0&lt;/td>
&lt;td>1 April 2026&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>v6.1&lt;/td>
&lt;td>in preparation as of this data sheet&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The suite splits into two system categories: &lt;strong>Datacenter&lt;/strong> and &lt;strong>Edge&lt;/strong>, the latter defined in the rules as everything that is not datacenter (&lt;a href="https://github.com/mlcommons/inference_policies/blob/master/inference_rules.adoc">inference_rules.adoc&lt;/a>). A Datacenter system has two requirements that do not apply in Edge:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Mandatory ECC&lt;/strong> on DRAM and HBM, active during all performance and accuracy runs. There is no requirement on SRAM.&lt;/li>
&lt;li>&lt;strong>Mandatory networking&lt;/strong> since round v3.0, with a minimum bandwidth computed from the achieved throughput. For Llama 3.1 405B the minimum ingress is &lt;code>throughput × 20000 × dtype_size&lt;/code> bytes/s; for Llama 2 70B the minimum egress is &lt;code>throughput × 1024 × dtype_size&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>Edge additionally allows &lt;strong>inferred results&lt;/strong>: a MultiStream derived from SingleStream counts as 8 times the p99 latency; an Offline derived from MultiStream, 8000 divided by the mean latency in milliseconds.&lt;/p>
&lt;h2 id="the-four-scenarios">The four scenarios&lt;/h2>
&lt;p>This is the normative table, transcribed from the rules:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Scenario&lt;/th>
&lt;th>Query generation&lt;/th>
&lt;th>Duration&lt;/th>
&lt;th>Samples/query&lt;/th>
&lt;th>Latency constraint&lt;/th>
&lt;th>Tail latency&lt;/th>
&lt;th>Reported metric&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>SingleStream&lt;/td>
&lt;td>The next query is issued when the SUT completes the previous one&lt;/td>
&lt;td>600 s&lt;/td>
&lt;td>1&lt;/td>
&lt;td>None&lt;/td>
&lt;td>90 %&lt;/td>
&lt;td>p90 latency with early stopping&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Server / Interactive&lt;/td>
&lt;td>LoadGen issues queries following a &lt;strong>Poisson distribution&lt;/strong>&lt;/td>
&lt;td>600 s&lt;/td>
&lt;td>1&lt;/td>
&lt;td>Benchmark-specific&lt;/td>
&lt;td>99 %&lt;/td>
&lt;td>Maximum Poisson parameter supported&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Offline&lt;/td>
&lt;td>All samples are delivered at the start in &lt;strong>a single query&lt;/strong>&lt;/td>
&lt;td>1 query, 600 s&lt;/td>
&lt;td>At least 24,576&lt;/td>
&lt;td>None&lt;/td>
&lt;td>N/A&lt;/td>
&lt;td>Measured throughput&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>MultiStream&lt;/td>
&lt;td>The next query is issued when the SUT completes the previous one&lt;/td>
&lt;td>600 s&lt;/td>
&lt;td>&lt;strong>8&lt;/strong>&lt;/td>
&lt;td>None&lt;/td>
&lt;td>99 %&lt;/td>
&lt;td>p99 query latency with early stopping&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Four operational clarifications that change how each number is interpreted:&lt;/p>
&lt;ul>
&lt;li>In &lt;strong>Server&lt;/strong>, LoadGen does not measure a latency: it runs a binary search over the target rate. For a given value it generates queries at that QPS with Poisson arrivals; if the run fails the latency gate, it lowers the value and repeats. The final published metric is, per the official FAQ, &lt;strong>scheduled samples per second&lt;/strong>, not completed samples nor the target entered by the user.&lt;/li>
&lt;li>In &lt;strong>MultiStream&lt;/strong>, the latency of a query is the &lt;strong>maximum&lt;/strong> of the latencies of its samples, and the 8 samples of each query are contiguous in the order in which they were loaded. The value &lt;code>multi_stream_samples_per_query = 8&lt;/code> is fixed in the official configuration.&lt;/li>
&lt;li>In &lt;strong>Offline&lt;/strong> there is no latency constraint at all. The rules themselves forbid techniques that only work in fixed-length experiments &lt;em>except in the Offline scenario&lt;/em>, which is a normative acknowledgement that an Offline result says nothing about behaviour under an SLO.&lt;/li>
&lt;li>The percentiles in the table are the &lt;strong>lower theoretical bound&lt;/strong> for runs with very many queries. With early stopping, the percentile actually computed is somewhat above the nominal one, as a penalty for processing few queries.&lt;/li>
&lt;/ul>
&lt;p>The mandatory scenarios depend on the benchmark. In Datacenter, the summarisation, question answering, text generation and VLM tasks require &lt;code>(Server | Interactive), Offline&lt;/code>, that is, the submitter chooses between Server and Interactive. Reasoning and recommendation require &lt;code>Server, Offline&lt;/code>. Medical segmentation, node classification, speech-to-text and RAG require only &lt;code>Offline&lt;/code>.&lt;/p>
&lt;h2 id="loadgen-what-it-measures-and-what-it-does-not">LoadGen: what it measures and what it does not&lt;/h2>
&lt;p>LoadGen is the module that generates the load and computes the metrics. Its use is mandatory for all submissions, and it must be compiled from a tagged and approved revision of the repository, unaltered; the README is explicit that local modifications of the C++ library are not accepted.&lt;/p>
&lt;p>Its four declared responsibilities are generating the queries according to the scenario, tracking the latency of each query, validating the accuracy of the results and computing the final metrics. Latency is defined as the time from when LoadGen was scheduled to pass a query to the system under test until it receives the response.&lt;/p>
&lt;p>Equally important is what it declares &lt;strong>out of scope&lt;/strong>: LoadGen does not know the model, does not know the data formats, cannot score accuracy and does not know the scenario constraints of the MLPerf rules. The consequence is written in its own README: being model-agnostic, it cannot enforce the MLPerf requirements, for example the target percentiles and latencies. Those limits are injected from &lt;code>mlperf.conf&lt;/code> and &lt;code>user.conf&lt;/code>. The justification for making it mandatory appears in the founding ISCA 2020 paper: it establishes a clear boundary between the components that belong to the submitter and those that belong to MLPerf, and it measures the performance of the complete system instead of that of a single piece.&lt;/p>
&lt;h3 id="duration-query-count-and-early-stopping">Duration, query count and early stopping&lt;/h3>
&lt;p>The minimum duration is 600,000 ms in all four scenarios. The minimum number of queries comes from a confidence interval table that the rules publish:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Tail percentile&lt;/th>
&lt;th>Confidence&lt;/th>
&lt;th>Margin of error&lt;/th>
&lt;th>Inferences&lt;/th>
&lt;th>Rounded&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>90 %&lt;/td>
&lt;td>99 %&lt;/td>
&lt;td>0.50 %&lt;/td>
&lt;td>23,886&lt;/td>
&lt;td>24,576&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>95 %&lt;/td>
&lt;td>99 %&lt;/td>
&lt;td>0.25 %&lt;/td>
&lt;td>50,425&lt;/td>
&lt;td>57,344&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>97 %&lt;/td>
&lt;td>99 %&lt;/td>
&lt;td>0.15 %&lt;/td>
&lt;td>85,811&lt;/td>
&lt;td>90,112&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>99 %&lt;/td>
&lt;td>99 %&lt;/td>
&lt;td>0.05 %&lt;/td>
&lt;td>262,742&lt;/td>
&lt;td>270,336&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The submission checker applies &lt;code>Server: 270336&lt;/code>, &lt;code>SingleStream: 1024&lt;/code> and &lt;code>MultiStream: 662&lt;/code>. For Offline, the minimum is set per benchmark: 24,576 on Llama 2 70B, 15,000 on Mixtral 8x7B, 13,368 on Llama 3.1 8B, 8,313 on Llama 3.1 405B, 4,388 on DeepSeek-R1, 1,633 on Whisper and 43 on 3D UNet.&lt;/p>
&lt;p>The &lt;strong>early stopping&lt;/strong> mechanism allows runs to be shortened while keeping the statistical guarantee. With tolerance &lt;code>d = 0&lt;/code> and confidence &lt;code>c = 0.99&lt;/code>, the algorithm resolves by binary search the smallest number of queries below the latency threshold that satisfies the criterion, given the number of queries observed above it.&lt;/p>
&lt;p>LoadGen&amp;rsquo;s &lt;strong>modes&lt;/strong> are &lt;code>SubmissionRun&lt;/code> (accuracy followed by performance), &lt;code>AccuracyOnly&lt;/code>, &lt;code>PerformanceOnly&lt;/code> and &lt;code>FindPeakPerformance&lt;/code>. The last, applicable only to Server, takes &lt;code>target_qps&lt;/code> as a lower bound if it passes, estimates the upper bound at double and doubles it until failure, and then does a binary search. In performance mode LoadGen selects queries uniformly at random with replacement from a set of size QSL; in accuracy mode it uses a copy of the validation dataset, each sample exactly once. One accuracy run must be executed for every performance result submitted, and the same code in both modes.&lt;/p>
&lt;p>The &lt;strong>seeds&lt;/strong> are announced four weeks before the deadline and the mandatory generator is Mersenne Twister 19937. They change every round: in v5.1, &lt;code>qsl_rng_seed = 1780908523862526354&lt;/code>; in v5.0 it was &lt;code>6023615788873153749&lt;/code>.&lt;/p>
&lt;h3 id="the-compliance-tests">The compliance tests&lt;/h3>
&lt;p>They are activated by placing an &lt;code>audit.config&lt;/code> file in the working directory, whose parameters &lt;strong>override&lt;/strong> those of &lt;code>mlperf.conf&lt;/code> and &lt;code>user.conf&lt;/code>. Their logs are mandatory in the submission package. The declared purpose is to detect anomalies, not to diagnose their cause.&lt;/p>
&lt;p>For the LLM benchmarks the required test is &lt;strong>TEST06&lt;/strong>, specifically against the end-of-sequence token &lt;em>exploit&lt;/em>. It runs 100 samples and demands three conditions: that the first token reported separately matches the first token of the model&amp;rsquo;s output, that the output ends with zero or a single EOS token, and that the number of tokens reported matches the real length of the generated sequence.&lt;/p>
&lt;h2 id="divisions-categories-and-what-can-be-touched">Divisions, categories and what can be touched&lt;/h2>
&lt;h3 id="the-three-divisions">The three divisions&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Closed&lt;/strong>: requires preprocessing, postprocessing and model equivalent to the reference implementation. It allows calibration for quantisation and &lt;strong>does not allow retraining&lt;/strong>. It is the only one that can use the MLPerf name unqualified.&lt;/li>
&lt;li>&lt;strong>Open&lt;/strong>: allows arbitrary preprocessing, postprocessing and model, including retraining. The accuracy, latency and scenario constraints &lt;strong>do not apply&lt;/strong>: instead, the accuracy obtained and the latency constraints under which the performance was obtained must be reported. The model may have any origin, be quantised in any way and be sparsified in any way. It must use the same validation dataset as the corresponding Closed and use all of it.&lt;/li>
&lt;li>&lt;strong>Network&lt;/strong>: inherits all the Closed requirements, applies only to Datacenter, and separates the LoadGen node from the system under test through a &lt;em>fabric&lt;/em>. The submitter&amp;rsquo;s dispatch library cannot preprocess, postprocess, &lt;strong>batch&lt;/strong>, pad or &lt;strong>cache&lt;/strong>. Bus interconnects are forbidden by name (PCIe, CXL, CCIX, HyperTransport, NVLink, QPI, UPI, ICI) and only Ethernet, IEEE 802.11, InfiniBand and 3GPP are admitted, with a requirement to work chassis to chassis at more than ten metres.&lt;/li>
&lt;/ul>
&lt;h3 id="the-availability-categories">The availability categories&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Category&lt;/th>
&lt;th>Hardware&lt;/th>
&lt;th>Software&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Available in cloud&lt;/td>
&lt;td>Available for cloud rental&lt;/td>
&lt;td>Available&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Available on premise&lt;/td>
&lt;td>Available for purchase&lt;/td>
&lt;td>Available&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Preview&lt;/td>
&lt;td>Must be available for the next submission, or the one after 140 days, whichever is longer&lt;/td>
&lt;td>Available except what is needed for substantially new hardware&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>RDI&lt;/td>
&lt;td>Does not meet the above&lt;/td>
&lt;td>Does not meet the above&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Available demands four cumulative conditions: price available, having been rented or shipped to at least one third party, public evidence of availability and reasonable availability to additional third parties on the submission date. A Preview result obliges a resubmission as Available with equal or better performance, tolerating up to &lt;strong>2 % degradation&lt;/strong> from noise; if there is no resubmission, the Preview result is &lt;strong>marked invalid&lt;/strong>. RDI components cannot be submitted as Available until the cycle after the next one, or 221 days, whichever is longer.&lt;/p>
&lt;h3 id="what-closed-allows-and-forbids">What Closed allows and forbids&lt;/h3>
&lt;p>MLPerf delivers the weights in fp16 or fp32. The central rule is that the submitter may perform purely mathematical and reproducible quantisation, using only the calibration data and the tensors of the delivered model, to any numerical format that reaches the required quality, and that the method must be described publicly at a level that allows it to be reproduced. The test against back doors is elegant: the description of the quantisation method must be &lt;em>much smaller&lt;/em> than the non-zero weights it produces.&lt;/p>
&lt;p>&lt;strong>Allowed&lt;/strong>, among other things: any framework or runtime, arbitrary data layout, varying the matrix multiplication algorithm, mathematically equivalent transformations, polynomial approximations of transcendentals, processing queries out of order within what the scenario admits, replacing dense operations with mathematically equivalent sparse operations, hand-picking different precisions per operation, fusing and unfusing, dynamic batching, and mixtures of experts combining weights with different quantisation.&lt;/p>
&lt;p>&lt;strong>Forbidden&lt;/strong>: replacing or supplementing weights wholesale, discarding non-zero weights, including pruning, caching queries or responses, coalescing identical queries, modifying weights during the timed portion, quantisation algorithms of size comparable to the weights they produce, hardcoding the total number of queries, using knowledge of the LoadGen implementation to predict peaks or troughs in the Server scenario, changing the number of search beams, and incorporating statistics from the performance or accuracy sets.&lt;/p>
&lt;p>Two clarifications that matter to anyone serving LLMs in production: the &lt;strong>KV cache&lt;/strong> is allowed just as in the reference model provided it is not applied &lt;strong>across queries&lt;/strong>; PagedAttention is admitted if the block is reused only within the batch; continuous or dynamic batching is allowed; and KV cache entries are treated as activations for quantisation purposes, and cannot be pruned. &lt;strong>Speculative decoding&lt;/strong> is only admitted in the benchmark and scenario combinations explicitly listed, with the reference head at the same precision, and implementations that artificially manipulate the acceptance rate are forbidden.&lt;/p>
&lt;h2 id="the-slos-almost-nobody-cites-ttft-and-tpot">The SLOs almost nobody cites: TTFT and TPOT&lt;/h2>
&lt;p>This is the point where an MLPerf table is most often misread. In the LLM benchmarks of the Server scenario, the constraint is not a request latency: the rules set &lt;code>target_latency = 0&lt;/code> and activate &lt;code>use_token_latencies = 1&lt;/code>, so that the gate is formed by &lt;strong>two simultaneous metrics&lt;/strong>, both evaluated at the &lt;strong>99th percentile&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>TTFT&lt;/strong> (&lt;em>time to first token&lt;/em>): latency of the first token.&lt;/li>
&lt;li>&lt;strong>TPOT&lt;/strong> (&lt;em>time per output token&lt;/em>): mean interval between all generated tokens.&lt;/li>
&lt;/ul>
&lt;p>The figures are in &lt;code>mlperf.conf&lt;/code> and change per round and per benchmark:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Benchmark (Server scenario)&lt;/th>
&lt;th>TTFT&lt;/th>
&lt;th>TPOT&lt;/th>
&lt;th>Round&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>llama2-70b&lt;/code>&lt;/td>
&lt;td>2000 ms&lt;/td>
&lt;td>200 ms&lt;/td>
&lt;td>v5.0, v5.1, v6.x&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>llama2-70b-interactive&lt;/code>&lt;/td>
&lt;td>&lt;strong>450 ms&lt;/strong>&lt;/td>
&lt;td>&lt;strong>40 ms&lt;/strong>&lt;/td>
&lt;td>v5.1, v6.x&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>mixtral-8x7b&lt;/code>&lt;/td>
&lt;td>2000 ms&lt;/td>
&lt;td>200 ms&lt;/td>
&lt;td>v5.0, v5.1, v6.x&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>llama3_1-405b&lt;/code>&lt;/td>
&lt;td>6000 ms&lt;/td>
&lt;td>175 ms&lt;/td>
&lt;td>v5.0, v5.1, v6.x&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>llama3_1-405b-interactive&lt;/code>&lt;/td>
&lt;td>4500 ms&lt;/td>
&lt;td>80 ms&lt;/td>
&lt;td>v6.x&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>llama3_1-8b&lt;/code>&lt;/td>
&lt;td>2000 ms&lt;/td>
&lt;td>100 ms&lt;/td>
&lt;td>v5.1, v6.x&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>llama3_1-8b-interactive&lt;/code>&lt;/td>
&lt;td>500 ms&lt;/td>
&lt;td>30 ms&lt;/td>
&lt;td>v6.x&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>deepseek-r1&lt;/code>&lt;/td>
&lt;td>2000 ms&lt;/td>
&lt;td>80 ms&lt;/td>
&lt;td>v5.1, v6.x&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>deepseek-r1-interactive&lt;/code>&lt;/td>
&lt;td>1500 ms&lt;/td>
&lt;td>15 ms&lt;/td>
&lt;td>v6.x&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>gpt-oss-120b&lt;/code>&lt;/td>
&lt;td>3000 ms&lt;/td>
&lt;td>80 ms&lt;/td>
&lt;td>v6.x&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>A TPOT of 40 ms is equivalent to 25 tokens per second per user, which is the order of magnitude of a conversational interface; one of 200 ms is equivalent to 5 tokens per second, which is a batch use case dressed up as a service. Two results for the same model under the Server and Interactive labels are not the same measurement. Two documented discrepancies between primary sources remain: the &lt;code>llama2-70b-interactive&lt;/code> variant does not appear in the &lt;code>mlperf.conf&lt;/code> tagged as v5.0 despite having been announced in that round, and in the v6.x cycle the TPOT of &lt;code>gpt-oss-120b-interactive&lt;/code> appears as 15 ms in &lt;code>mlperf.conf&lt;/code> and as 20 ms in the text of the rules.&lt;/p>
&lt;p>For contrast, the constraints of the non-LLM benchmarks in the Server scenario are conventional request latencies: ResNet-50 15 ms, RetinaNet 100 ms, BERT 130 ms, DLRMv2 60 ms, DLRMv3 80 ms, RNN-T 1000 ms, GPT-J and Stable Diffusion XL 20,000 ms.&lt;/p>
&lt;h2 id="quality-the-99--and-the-token-count">Quality: the 99 % and the token count&lt;/h2>
&lt;p>The quality targets are expressed relative to the reference model, never in absolute terms, and each benchmark demands one variant, the other or both. In the current Datacenter suite, 3D UNet, Llama 3.1 8B and Whisper ask for 99 % and 99.9 % of FP32, which generates two distinct results; Llama 2 70B asks only for 99.9 %; Llama 3.1 405B, Mixtral, DeepSeek-R1, GPT-OSS-120B, Qwen3-VL, RGAT and WAN-2.2 ask only for 99 %; and E2E-RAG is the exception at 97 %. In the checker this materialises as separate benchmarks (&lt;code>bert-99&lt;/code> and &lt;code>bert-99.9&lt;/code>), each with its computed numerical threshold.&lt;/p>
&lt;p>On top of that metric there is a second LLM-specific constraint that is cited very rarely: the generation length is audited as well.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Benchmark&lt;/th>
&lt;th>Length constraint&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Llama 2 70B&lt;/td>
&lt;td>tokens per sample &amp;gt; 90 % of 294.45&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Llama 3.1 405B&lt;/td>
&lt;td>tokens per sample between 90 % and 110 % of 684.68&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Mixtral 8x7B&lt;/td>
&lt;td>tokens per sample between 90 % and 110 % of 144.84&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Llama 3.1 8B&lt;/td>
&lt;td>total generated length &amp;gt; 90 % of 8,167,644&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The FAQ settles the obvious shortcut: reducing the maximum output length below the reference is not allowed, and truncating tokens to improve performance or reach the accuracy target &lt;strong>is not permitted&lt;/strong>. The inference parameters are fixed in Closed (&lt;code>max_new_tokens = 1024&lt;/code> on Llama 2 70B, &lt;code>20000&lt;/code> on Llama 3.1 405B and DeepSeek-R1), as is the decoding algorithm: greedy search in the Llama family, Mixtral and DeepSeek-R1; sampling with &lt;code>temperature = 1.0&lt;/code> and &lt;code>top_p = 1.0&lt;/code> in GPT-OSS-120B and Qwen3-VL. Accuracy is reported to &lt;strong>five significant figures&lt;/strong> with round-half-to-even.&lt;/p>
&lt;h2 id="the-current-datacenter-suite">The current Datacenter suite&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Area&lt;/th>
&lt;th>Task&lt;/th>
&lt;th>Model&lt;/th>
&lt;th>Dataset&lt;/th>
&lt;th>QSL&lt;/th>
&lt;th>Required quality&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Vision&lt;/td>
&lt;td>Medical segmentation&lt;/td>
&lt;td>3D UNet&lt;/td>
&lt;td>KiTS 2019&lt;/td>
&lt;td>42&lt;/td>
&lt;td>99 % and 99.9 % of FP32 (DICE 0.86330)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Language&lt;/td>
&lt;td>Summarisation&lt;/td>
&lt;td>Llama 3.1 8B&lt;/td>
&lt;td>CNN DailyMail v3.0.0&lt;/td>
&lt;td>13,368&lt;/td>
&lt;td>99 % and 99.9 % of FP32&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Language&lt;/td>
&lt;td>Question answering&lt;/td>
&lt;td>Llama 2 70B&lt;/td>
&lt;td>OpenOrca&lt;/td>
&lt;td>24,576&lt;/td>
&lt;td>99.9 % of FP32&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Language&lt;/td>
&lt;td>Text generation&lt;/td>
&lt;td>Llama 3.1 405B&lt;/td>
&lt;td>LongBench, Ruler, GovReport&lt;/td>
&lt;td>8,313&lt;/td>
&lt;td>99 % of FP16&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Language&lt;/td>
&lt;td>QA, maths and code&lt;/td>
&lt;td>Mixtral 8x7B&lt;/td>
&lt;td>OpenOrca, GSM8K, MBXP&lt;/td>
&lt;td>15,000&lt;/td>
&lt;td>99 % of FP16&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Language&lt;/td>
&lt;td>Reasoning&lt;/td>
&lt;td>DeepSeek-R1&lt;/td>
&lt;td>&lt;code>mlperf_deepseek_r1&lt;/code>&lt;/td>
&lt;td>4,388&lt;/td>
&lt;td>99 % of FP16 (exact match 81.9132 %)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Language&lt;/td>
&lt;td>QA, maths and code&lt;/td>
&lt;td>GPT-OSS-120B&lt;/td>
&lt;td>AIME25, GPQA Diamond, LiveCodeBench v6&lt;/td>
&lt;td>6,396&lt;/td>
&lt;td>99 % of 83.13 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Vision&lt;/td>
&lt;td>Vision-language model&lt;/td>
&lt;td>Qwen3-VL-235B-A22B&lt;/td>
&lt;td>Shopify product catalogue&lt;/td>
&lt;td>48,289&lt;/td>
&lt;td>99 % of BF16 (hierarchical F1 0.7824)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Commerce&lt;/td>
&lt;td>Recommendation&lt;/td>
&lt;td>DLRMv3&lt;/td>
&lt;td>Synthetic Streaming 100B&lt;/td>
&lt;td>34,996&lt;/td>
&lt;td>99.9 % of FP32&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Generative&lt;/td>
&lt;td>Text to video&lt;/td>
&lt;td>WAN-2.2-T2V-A14B&lt;/td>
&lt;td>VBench prompts&lt;/td>
&lt;td>248&lt;/td>
&lt;td>99 % of BF16 (VBench 69.7752)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Graphs&lt;/td>
&lt;td>Node classification&lt;/td>
&lt;td>RGAT&lt;/td>
&lt;td>IGBH&lt;/td>
&lt;td>788,379&lt;/td>
&lt;td>99 % of FP32 (72.86 %)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Audio&lt;/td>
&lt;td>Speech to text&lt;/td>
&lt;td>Whisper&lt;/td>
&lt;td>LibriSpeech&lt;/td>
&lt;td>1,633&lt;/td>
&lt;td>99 % and 99.9 % of FP32 (WER 2.0671 %)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Language&lt;/td>
&lt;td>End-to-end RAG&lt;/td>
&lt;td>E2E-RAG&lt;/td>
&lt;td>FRAMES&lt;/td>
&lt;td>824&lt;/td>
&lt;td>97 % of FP32&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The &lt;strong>E2E-RAG&lt;/strong> benchmark deserves attention from anyone designing a RAG platform, because it fixes the whole pipeline: a FAISS HNSW index with mandatory parameters &lt;code>M = 32&lt;/code>, &lt;code>efConstruction = 200&lt;/code> and &lt;code>efSearch = 100&lt;/code>; e5-base-v2 embeddings; ColBERTv2 reranking; generation and query rewriting with GPT-OSS-120B; evaluation with Llama 3.1 8B as judge; and a maximum of 5 retrieval iterations, mandatory for all submitters. Model loading is not timed; building the vector database is.&lt;/p>
&lt;p>The definition of &lt;em>sample&lt;/em> changes per model and is a frequent source of confusion: in the LLMs it is a sequence, in DLRMv3 it is a request with a user history and &lt;strong>2048 candidates&lt;/strong>, in WAN-2.2 it is a pair of positive and negative prompts, and in PointPainting it is five images and a lidar point cloud.&lt;/p>
&lt;h2 id="how-to-read-a-results-row">How to read a results row&lt;/h2>
&lt;p>The columns of the official table in the Closed division are &lt;em>Submitter, Software, System, Benchmark Results, Processor/Count, Details, Accelerator/Count&lt;/em> and &lt;em>Code&lt;/em>. The Open division adds &lt;em>Model Used&lt;/em> and &lt;em>Notes&lt;/em>. Rows with power measurement add &lt;em>System Power&lt;/em> in Server and Offline, or &lt;em>Energy Per Stream&lt;/em> in the stream scenarios. Any citation must use the identifier in the format &lt;code>major-version.minor-version.entry.benchmark&lt;/code>, of the style &lt;code>5.1-0053&lt;/code>, and carry a footnote with suite, version, division, benchmark, scenario, date and source.&lt;/p>
&lt;h3 id="per-accelerator-is-not-an-official-metric">Per-accelerator is not an official metric&lt;/h3>
&lt;p>&lt;strong>There is no per-accelerator column.&lt;/strong> It is a derived metric, and the MLCommons messaging guidelines are blunt: any comparison based on a different or derived metric, such as power, cost, model size or accuracy, must make the basis of comparison clear in the text and in a footnote, and secondary and derived metrics cannot be presented as official or verified MLPerf metrics. NVIDIA itself states this with the standard formula in its round blogs: per-GPU performance is not a primary MLPerf Inference metric and is computed by dividing the reported throughput by the number of reported accelerators. The same applies to combining results from several benchmarks: MLCommons allows it but &lt;strong>does not endorse it&lt;/strong>, and the composite cannot be presented as an official result.&lt;/p>
&lt;h3 id="the-comparison-rules">The comparison rules&lt;/h3>
&lt;ul>
&lt;li>MLPerf results can only be compared &lt;strong>with compatible MLPerf results&lt;/strong>: same benchmark, same scenario and compatible versions per the normative compatibility table.&lt;/li>
&lt;li>MLPerf results cannot be compared with non-MLPerf results.&lt;/li>
&lt;li>When comparing, any difference in version, division, category, verification status, scenario or number of chips must be clearly identified. When comparing Open with Closed, it must be identified in what sense the Open result would not qualify as Closed.&lt;/li>
&lt;li>Submitters cannot publish results of a version before its official date; non-submitters must wait &lt;strong>two weeks&lt;/strong> from that date.&lt;/li>
&lt;li>The sanctions regime goes as far as barring an infringer from submitting results in the future and marking their results as non-compliant permanently in the database, with a deadline of &lt;strong>three working days&lt;/strong> to withdraw the infringing content.&lt;/li>
&lt;/ul>
&lt;h3 id="how-much-audit-sits-behind-a-row">How much audit sits behind a row&lt;/h3>
&lt;p>In each round up to two submissions are audited: one chosen at random from all of them and zero or one chosen by the review committee. And there is a constraint that conditions the reading of the whole table: only Available submissions in the Closed division are auditable. Preview, RDI and Open fall outside the process. There is an exemption from the random audit if the system is equivalent to another already audited and neither the aggregate performance nor the per-accelerator performance differ by more than 10 % from those of the previous audit. The deadlines are 28 days to select an auditor, 30 for the report after signing the confidentiality agreements and around 90 days for the complete process, with &lt;strong>two days&lt;/strong> of hardware access for the auditor. The rules close with three sentences that define the standard of proof: results that cannot be replicated are not valid results, benchmark detection is not allowed and input-based optimisation is not allowed either.&lt;/p>
&lt;h2 id="the-recent-rounds-in-figures">The recent rounds, in figures&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Round&lt;/th>
&lt;th>Organisations&lt;/th>
&lt;th>Performance results&lt;/th>
&lt;th>Power results&lt;/th>
&lt;th>New benchmarks&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>v4.0&lt;/td>
&lt;td>23&lt;/td>
&lt;td>more than 8,500&lt;/td>
&lt;td>900&lt;/td>
&lt;td>2&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>v4.1&lt;/td>
&lt;td>22&lt;/td>
&lt;td>964&lt;/td>
&lt;td>31&lt;/td>
&lt;td>1&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>v5.0&lt;/td>
&lt;td>23&lt;/td>
&lt;td>17,457&lt;/td>
&lt;td>n/a&lt;/td>
&lt;td>4&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>v5.1&lt;/td>
&lt;td>27&lt;/td>
&lt;td>n/a&lt;/td>
&lt;td>2&lt;/td>
&lt;td>3&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>v6.0&lt;/td>
&lt;td>24&lt;/td>
&lt;td>n/a&lt;/td>
&lt;td>n/a&lt;/td>
&lt;td>5 of 11 Datacenter tests&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>These counts do not form a time series: the counting criteria differ between press releases and none documents the criterion, to the point that v4.0 and v4.1 differ by a factor close to nine.&lt;/p>
&lt;p>The published performance jumps are comparable within each announcement. Between v4.0 and v5.0, twelve months apart, the number of Llama 2 70B submissions multiplied by 2.5, the &lt;strong>median&lt;/strong> score doubled and the best score was &lt;strong>3.3 times faster&lt;/strong>. Between v5.0 and v5.1, in six months, the best systems improved &lt;strong>by up to 50 %&lt;/strong> in some scenarios. Round v6.0 changed axis and its press release talks about scale rather than speed: 30 % more multi-node submissions, 10 % of the systems with more than ten nodes against 2 % in the previous round, and a system larger than 72 nodes and 288 accelerators, quadrupling the previous maximum node count.&lt;/p>
&lt;p>Hardware that debuted in each round: MI300X, TPU v6e, Xeon Granite Rapids and B200 in v4.1; MI325X, Xeon 6980P, GB200 and Jetson AGX Thor in v5.0; MI355X, Intel Arc Pro B60, GB300 and RTX Pro 6000 Blackwell Server Edition in v5.1.&lt;/p>
&lt;h2 id="what-mlperf-inference-does-not-measure">What MLPerf Inference does not measure&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Cost.&lt;/strong> There is no cost or TCO metric, and cost is explicitly classified as a derived metric that cannot be presented as official.&lt;/li>
&lt;li>&lt;strong>Energy, except as an optional extension.&lt;/strong> MLPerf Power is regulated in a separate document, requires measuring at the wall with the power group&amp;rsquo;s workflow and PTDaemon, and forbids any other method. Its real adoption is marginal: 2 power submissions in v5.1 against 27 participating organisations. In addition, MLCommons bounds what that figure means: the measured power is only valid for the benchmark it accompanies, and any other reference to power, such as a TDP setting or a power supply rating, is neither measured nor validated by MLCommons. The messaging rule forbids submitters from publishing per-watt normalised comparisons using any proxy other than the measured power.&lt;/li>
&lt;li>Configurations not optimised by the vendor. The bias is acknowledged in the audit rule itself, which contemplates submissions whose performance is not consistent with the known characteristics of the hardware, or where the committee lacks visibility into how it was achieved, or where hardware and software are not reasonably available to the public.&lt;/li>
&lt;li>&lt;strong>Barrier to entry.&lt;/strong> Only MLCommons members and &lt;em>test partners&lt;/em> can submit results for review. Anyone measuring with the same code without submitting must label every figure as &lt;strong>unverified&lt;/strong> with the corresponding legend.&lt;/li>
&lt;/ul>
&lt;h2 id="usage-flow-for-an-on-premise-platform">Usage flow for an on-premise platform&lt;/h2>
&lt;p>MLPerf Inference is useful in a purchasing decision if it is used for what it is, a test bench with written rules, and not as a ranking.&lt;/p>
&lt;ol>
&lt;li>Filter by division and category before looking at any number: keep Closed and Available. A Preview or RDI result describes hardware that cannot yet be bought, and neither of the two is auditable.&lt;/li>
&lt;li>Choose the scenario that matches the load pattern: Server or Interactive if there are users waiting, Offline if the work is batch. An Offline result does not authorise promising a latency.&lt;/li>
&lt;li>Read the SLO before the throughput: in any LLM benchmark, the number of queries per second only means something alongside its TTFT/TPOT pair. The same machine publishes very different figures under Server and under Interactive.&lt;/li>
&lt;li>Check the quality variant: 99 % and 99.9 % are different results for the same model, and the second usually costs performance.&lt;/li>
&lt;li>Translate to your own configuration carefully: dividing by the number of accelerators is a derived metric, not an official one, and it has to be declared as such.&lt;/li>
&lt;li>Close the gap MLPerf leaves open with your own measurement: cost, energy and behaviour under real traffic. That is exactly the function of the reproducible harness and of the track B bench tools, and the reason no platform decision stands on a public table alone.&lt;/li>
&lt;/ol>
&lt;h2 id="cross-links-from-the-benchmarking-track">Cross-links from the benchmarking track&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/llm-inference-benchmarking-frameworks-metrics-state-of-the-art/">B1/B2 — LLM inference benchmarking: frameworks, metrics and state of the art&lt;/a>: the TTFT, TPOT and goodput metrics outside the MLPerf corset, and which tool measures each one.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/llm-benchmark-tool-catalogue-practical-deep-dive/">B2 — LLM benchmark tool catalogue&lt;/a>: the tools with which you reproduce at home what MLPerf standardises.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/guidellm-validating-slo-under-load-sizing-knee/">B3 — GuideLLM and SLO validation under load&lt;/a>: the practical equivalent of LoadGen&amp;rsquo;s binary search in the Server scenario.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/measurement-bias-reproducibility-llm-benchmarks/">B6 — Measurement bias and reproducibility&lt;/a>: why LoadGen exists, told from the side of what happens when there is none.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/llm-serving-engines-pareto-frontier-comparison/">B8 — Serving engines compared on the Pareto frontier&lt;/a>: the comparison MLPerf does not make, with engines instead of systems.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/mlperf-power-energy-efficiency-benchmark/">C4 — MLPerf Power&lt;/a>: the energy extension of this same machinery, with its certified measurement at the wall.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="see-also">See also&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/reproducible-harness-cost-performance-energy-experiment/">The reproducible harness: cost, performance and energy in a single auditable experiment&lt;/a> — how to build at home the auditable equivalent of a submission, measuring on top of that what MLPerf leaves out.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/slo-to-number-of-gpus-sizing-justifying-inference-hardware/">Sizing and justifying the GPU investment&lt;/a> — the step from a throughput figure under an SLO to the number of accelerators and the return.&lt;/li>
&lt;/ul>
&lt;h2 id="sources">Sources&lt;/h2>
&lt;ul>
&lt;li>MLCommons, &lt;em>MLPerf Inference Working Group&lt;/em> — &lt;a href="https://mlcommons.org/working-groups/benchmarks/inference/">https://mlcommons.org/working-groups/benchmarks/inference/&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>MLPerf Inference Rules (inference_rules.adoc)&lt;/em> — &lt;a href="https://github.com/mlcommons/inference_policies/blob/master/inference_rules.adoc">https://github.com/mlcommons/inference_policies/blob/master/inference_rules.adoc&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>MLPerf Inference Power Measurement (power_measurement.adoc)&lt;/em> — &lt;a href="https://github.com/mlcommons/inference_policies/blob/master/power_measurement.adoc">https://github.com/mlcommons/inference_policies/blob/master/power_measurement.adoc&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>MLPerf Submission Rules (submission_rules.adoc)&lt;/em> — &lt;a href="https://github.com/mlcommons/policies/blob/master/submission_rules.adoc">https://github.com/mlcommons/policies/blob/master/submission_rules.adoc&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>MLPerf Results Messaging Guidelines&lt;/em> — &lt;a href="https://github.com/mlcommons/policies/blob/master/MLPerf_Results_Messaging_Guidelines.adoc">https://github.com/mlcommons/policies/blob/master/MLPerf_Results_Messaging_Guidelines.adoc&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>LoadGen README&lt;/em> — &lt;a href="https://github.com/mlcommons/inference/blob/master/loadgen/README.md">https://github.com/mlcommons/inference/blob/master/loadgen/README.md&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>loadgen/test_settings.h&lt;/em> — &lt;a href="https://github.com/mlcommons/inference/blob/master/loadgen/test_settings.h">https://github.com/mlcommons/inference/blob/master/loadgen/test_settings.h&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>loadgen/mlperf.conf (master)&lt;/em> — &lt;a href="https://github.com/mlcommons/inference/blob/master/loadgen/mlperf.conf">https://github.com/mlcommons/inference/blob/master/loadgen/mlperf.conf&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>loadgen/mlperf.conf (tag v5.1)&lt;/em> — &lt;a href="https://github.com/mlcommons/inference/blob/v5.1/loadgen/mlperf.conf">https://github.com/mlcommons/inference/blob/v5.1/loadgen/mlperf.conf&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>loadgen/mlperf.conf (tag v5.0)&lt;/em> — &lt;a href="https://github.com/mlcommons/inference/blob/v5.0/loadgen/mlperf.conf">https://github.com/mlcommons/inference/blob/v5.0/loadgen/mlperf.conf&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>tools/submission/submission_checker.py (tag v5.0)&lt;/em> — &lt;a href="https://github.com/mlcommons/inference/blob/v5.0/tools/submission/submission_checker.py">https://github.com/mlcommons/inference/blob/v5.0/tools/submission/submission_checker.py&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>compliance/nvidia TEST06 README (tag v5.1)&lt;/em> — &lt;a href="https://github.com/mlcommons/inference/blob/v5.1/compliance/nvidia/TEST06/README.md">https://github.com/mlcommons/inference/blob/v5.1/compliance/nvidia/TEST06/README.md&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>Benchmark results: Inference Datacenter&lt;/em> — &lt;a href="https://mlcommons.org/benchmarks/inference-datacenter/">https://mlcommons.org/benchmarks/inference-datacenter/&lt;/a>&lt;/li>
&lt;li>Reddi et al., &lt;em>MLPerf Inference Benchmark&lt;/em>, ISCA 2020 — &lt;a href="https://arxiv.org/abs/1911.02549">https://arxiv.org/abs/1911.02549&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>MLPerf Inference v5.0 Benchmark Results&lt;/em> (abril 2025) — &lt;a href="https://www.businesswire.com/news/home/20250402313932/en/MLCommons-Releases-New-MLPerf-Inference-v5.0-Benchmark-Results">https://www.businesswire.com/news/home/20250402313932/en/MLCommons-Releases-New-MLPerf-Inference-v5.0-Benchmark-Results&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>MLPerf Inference v5.1 Benchmark Results&lt;/em> (septiembre 2025) — &lt;a href="https://www.globenewswire.com/news-release/2025/09/09/3147136/0/en/MLCommons-Releases-New-MLPerf-Inference-v5-1-Benchmark-Results.html">https://www.globenewswire.com/news-release/2025/09/09/3147136/0/en/MLCommons-Releases-New-MLPerf-Inference-v5-1-Benchmark-Results.html&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>MLPerf Inference v6.0 Benchmark Results&lt;/em> (abril 2026) — &lt;a href="https://www.globenewswire.com/news-release/2026/04/01/3266801/0/en/MLCommons-Releases-New-MLPerf-Inference-v6-0-Benchmark-Results.html">https://www.globenewswire.com/news-release/2026/04/01/3266801/0/en/MLCommons-Releases-New-MLPerf-Inference-v6-0-Benchmark-Results.html&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>MLPerf Inference v4.1 Benchmark Results&lt;/em> (agosto 2024) — &lt;a href="https://www.businesswire.com/news/home/20240828886616/en/New-MLPerf-Inference-v4.1-Benchmark-Results-Highlight-Rapid-Hardware-and-Software-Innovations-in-Generative-AI-Systems">https://www.businesswire.com/news/home/20240828886616/en/New-MLPerf-Inference-v4.1-Benchmark-Results-Highlight-Rapid-Hardware-and-Software-Innovations-in-Generative-AI-Systems&lt;/a>&lt;/li>
&lt;li>NVIDIA Developer Blog, &lt;em>NVIDIA Blackwell delivers massive performance leaps in MLPerf Inference v5.0&lt;/em> — &lt;a href="https://developer.nvidia.com/blog/nvidia-blackwell-delivers-massive-performance-leaps-in-mlperf-inference-v5-0/">https://developer.nvidia.com/blog/nvidia-blackwell-delivers-massive-performance-leaps-in-mlperf-inference-v5-0/&lt;/a>&lt;/li>
&lt;li>NVIDIA Developer Blog, &lt;em>NVIDIA Blackwell Ultra sets new inference records in MLPerf debut&lt;/em> — &lt;a href="https://developer.nvidia.com/blog/nvidia-blackwell-ultra-sets-new-inference-records-in-mlperf-debut/">https://developer.nvidia.com/blog/nvidia-blackwell-ultra-sets-new-inference-records-in-mlperf-debut/&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>MLPerf Automotive&lt;/em> (octubre 2025) — &lt;a href="https://arxiv.org/html/2510.27065v1">https://arxiv.org/html/2510.27065v1&lt;/a>&lt;/li>
&lt;li>Tschand et al., &lt;em>MLPerf Power: Benchmarking the Energy Efficiency of Machine Learning Systems from Microwatts to Megawatts&lt;/em> — &lt;a href="https://arxiv.org/abs/2410.12032">https://arxiv.org/abs/2410.12032&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Capacity planning for on-premise LLM inference: how to size GPUs from an SLO</title><link>https://blog.lo0.es/en/posts/capacity-planning-on-premise-llm-inference/</link><pubDate>Mon, 01 Jun 2026 15:00:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/capacity-planning-on-premise-llm-inference/</guid><description>&lt;blockquote>
&lt;p>This post complements the ones on &lt;a href="https://blog.lo0.es/en/posts/kv-cache-working-memory-llm-inference/">KV cache&lt;/a> (the piece that dominates the VRAM budget), &lt;a href="https://blog.lo0.es/en/posts/continuous-batching-orca-vllm-chunked-prefill-goodput/">Continuous batching&lt;/a> (what defines the effective utilisation of the compute) and &lt;a href="https://blog.lo0.es/en/posts/anatomy-on-premise-llm-inference-stack-seven-layers/">Seven layers of the stack&lt;/a> (the pieces the sizing takes for granted). Before reading this one, make sure your team has written down the SLOs it is going to chase; without that input the calculation is not defensible.&lt;/p>
&lt;/blockquote>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>LLM inference capacity planning does not answer &amp;ldquo;how many tokens per second does a GPU give&amp;rdquo; — that question has no universal answer, because throughput depends on concurrency, the prefill/decode split, context length, the inference engine and quantisation. The right question has three inputs (&lt;strong>SLO&lt;/strong>: TTFT P95, TPOT P95, sustained RPS), a hardware reference (GPU model, VRAM, HBM bandwidth, effective FLOPs) and a model (parameters, GQA/MHA/MoE architecture, weight format). The calculation resolves into two coupled budgets that cross each other. &lt;strong>VRAM budget&lt;/strong>: from the GPU&amp;rsquo;s total you subtract model weights and activations, what remains is the &lt;strong>KV cache budget&lt;/strong>, and from there you derive the &lt;strong>maximum concurrency&lt;/strong> possible at the average context you expect. &lt;strong>Time budget&lt;/strong>: the engine (vLLM, SGLang, TensorRT-LLM) has a tokens/s ceiling in decode given by HBM bandwidth and another in prefill given by useful FLOPs; from there you derive the &lt;strong>expected TPOT&lt;/strong> and, dividing prefill_tokens by prefill throughput, the &lt;strong>expected TTFT&lt;/strong>. Both budgets must meet the SLO &lt;strong>simultaneously&lt;/strong>: whichever is tighter dictates the sizing. On the Llama 70B BF16 example with tensor parallel 4 on 4×H100 SXM, a single replica saturates at ~28 concurrent requests and delivers ~3,200 tokens/s of aggregate decode with a median TPOT of 35 ms; for 200 sustained RPS at a profile of 800 prompt tokens + 250 of output, you need between 4 and 5 replicas with a 25 % cushion over the observed peak. Quantisation (FP8 → INT4) divides VRAM cost and decode time by between 1.5 and 4×, but it degrades quality measurably — it is not assumed free, it is validated with evals. The five habitual traps: confusing the mean with P95, ignoring the prefill/decode split of the real workload, sizing without head-room for retraining or rollback, forgetting that a GPU at 100 % SM util means nothing if the HBM is saturated, and not documenting the assumptions behind the calculation (a sizing with no written assumptions is a throwaway calculation).&lt;/p>
&lt;h2 id="you-are-here-deploy-with-one-foot-in-observe">You are here: DEPLOY (with one foot in OBSERVE)&lt;/h2>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 90" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="you are here: Deploy with one foot in Observe">
&lt;style>.box{stroke:#444;stroke-width:1.4;rx:6}.active{fill:#ffb347;stroke-width:3}.semiactive{fill:#ffe1b3;stroke-width:2}.idle{fill:#f4f4f4}.lbl{font:600 12px sans-serif;fill:#222}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#cpm)}.cyc{stroke:#888;stroke-width:1.2;fill:none;stroke-dasharray:4 2;marker-end:url(#cpm)}&lt;/style>
&lt;defs>&lt;marker id="cpm" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="#666"/>&lt;/marker>&lt;/defs>
&lt;text x="390" y="20" text-anchor="middle" class="lbl">You are here: capacity planning · closes DEPLOY and opens the conversation with OBSERVE&lt;/text>
&lt;rect x="30" y="35" width="110" height="35" class="box idle"/>&lt;text x="85" y="58" text-anchor="middle" class="lbl">1 · Data&lt;/text>
&lt;rect x="155" y="35" width="110" height="35" class="box idle"/>&lt;text x="210" y="58" text-anchor="middle" class="lbl">2 · Tune&lt;/text>
&lt;rect x="280" y="35" width="110" height="35" class="box idle"/>&lt;text x="335" y="58" text-anchor="middle" class="lbl">3 · Eval&lt;/text>
&lt;rect x="405" y="35" width="110" height="35" class="box active"/>&lt;text x="460" y="58" text-anchor="middle" class="lbl">4 · Deploy&lt;/text>
&lt;rect x="530" y="35" width="110" height="35" class="box semiactive"/>&lt;text x="585" y="58" text-anchor="middle" class="lbl">5 · Observe&lt;/text>
&lt;rect x="655" y="35" width="110" height="35" class="box idle"/>&lt;text x="710" y="58" text-anchor="middle" class="lbl">6 · Retrain&lt;/text>
&lt;path class="arr" d="M140,52 L155,52"/>&lt;path class="arr" d="M265,52 L280,52"/>&lt;path class="arr" d="M390,52 L405,52"/>&lt;path class="arr" d="M515,52 L530,52"/>&lt;path class="arr" d="M640,52 L655,52"/>
&lt;path class="cyc" d="M710,72 L710,82 L85,82 L85,72"/>
&lt;/svg>
&lt;/div>
&lt;p>Capacity planning is a piece with dual residency. It lives in &lt;strong>DEPLOY&lt;/strong> because without a valid sizing you do not buy hardware or configure the inference engine. But its &lt;strong>input is real observations&lt;/strong>: the distribution of prompt and output lengths, the prefill/decode mix of the workload, the real P95s already being seen in pre-production. Without that data the calculation is a napkin sketch, defensible only until the first customer arrives who does not fit the assumed average.&lt;/p>
&lt;h2 id="the-analogy-the-hotel-with-variable-sized-rooms">The analogy: the hotel with variable-sized rooms&lt;/h2>
&lt;p>Imagine a hotel where the rooms have no fixed size: each guest pays for the square metres they need, and the building&amp;rsquo;s floor plan reorganises itself dynamically to accommodate whoever arrives. Management wants to maximise occupancy, but it has two real constraints and one quality metric.&lt;/p>
&lt;p>&lt;strong>Constraint 1 — physical space.&lt;/strong> The floor has 1,000 m² in total. If a family comes in needing 200 m², that family occupies that surface and it cannot be handed to the next guest. The largest room limits how many simultaneous guests fit.&lt;/p>
&lt;p>&lt;strong>Constraint 2 — service staff.&lt;/strong> There are 10 receptionists. Each can handle the check-in of one guest every two minutes. When 60 guests arrive within an hour, the last ones wait in a queue; the time from walking into reception to receiving their key depends on how many are ahead of them.&lt;/p>
&lt;p>&lt;strong>Quality metric — a promise about time.&lt;/strong> The brochure says &amp;ldquo;check-in in under 15 minutes&amp;rdquo;. If too many guests arrive at once, that promise breaks even if there is physical space free.&lt;/p>
&lt;p>The physical space is the GPU&amp;rsquo;s VRAM. Each room is a request with its KV cache (larger the longer the conversation). The receptionists are the compute units (Streaming Multiprocessors + Tensor Cores). The check-in is the prefill phase; the nights the guest spends afterwards are the decode steps. The 15-minute promise is the TTFT P95 SLO.&lt;/p>
&lt;p>The hotel&amp;rsquo;s capacity planning is exactly this: given the expected guest profile (how many arrive per hour, how much space they ask for on average, how many minutes of waiting they tolerate), work out how many floors and how many receptionists are needed. It is not done by estimating &amp;ldquo;rooms per hour&amp;rdquo; in the abstract; it is done by crossing the two budgets with the promise about time. The analogy holds up the calculation all the way to the end.&lt;/p>
&lt;h2 id="the-three-slo-inputs">The three SLO inputs&lt;/h2>
&lt;p>Before putting a single number on the sheet, you have to write down the three dimensions of the SLO. Without this, the calculation is aesthetics, not engineering.&lt;/p>
&lt;p>&lt;strong>TTFT P95 (Time-To-First-Token).&lt;/strong> The time from the client sending the request until it receives the first token. It is dominated by the prefill phase (processing the whole prompt in one go) plus the scheduler queue. For conversational chat, a reasonable target sits between 0.5 and 2 seconds P95. For coding assistants with large prompts (5–10 K tokens of context), between 2 and 4 s P95. Below 500 ms you enter UX territory for voice-style conversations, but that demands serious architectural compromises.&lt;/p>
&lt;p>&lt;strong>TPOT P95 (Time-Per-Output-Token).&lt;/strong> The time between consecutive tokens during decode. It dominates the &amp;ldquo;perceived fluency&amp;rdquo; of streaming. Above 80 ms/token the human reader perceives pauses; below 30 ms/token the output flows faster than it can be read. The usual industry target: 40–60 ms P95.&lt;/p>
&lt;p>&lt;strong>Sustained RPS meeting the SLO.&lt;/strong> The throughput the system must support &lt;strong>without violating&lt;/strong> TTFT or TPOT. This is DistServe&amp;rsquo;s key metric, called &lt;strong>goodput&lt;/strong> (see &lt;a href="https://blog.lo0.es/en/posts/continuous-batching-orca-vllm-chunked-prefill-goodput/">Continuous batching&lt;/a>). &amp;ldquo;200 RPS peak&amp;rdquo; is not the same as &amp;ldquo;200 RPS with TTFT P95 ≤ 1.5 s&amp;rdquo;. Without the SLO condition, the RPS number means nothing.&lt;/p>
&lt;p>These three dimensions come with a &lt;strong>workload profile&lt;/strong>: the distribution of prompt and output lengths. Medians are not enough; you need P50, P95, P99. A badly measured profile is the main reason sizings fail.&lt;/p>
&lt;h2 id="the-central-formula-two-budgets-that-cross">The central formula: two budgets that cross&lt;/h2>
&lt;p>The calculation resolves into two independent sums that are then crossed. The smaller of the two rules.&lt;/p>
&lt;h3 id="vram-budget">VRAM budget&lt;/h3>
&lt;p>For a GPU with total VRAM $V$, the space available for KV cache is:&lt;/p>
$$V_{\text{kv}} = V - V_{\text{model}} - V_{\text{activations}} - V_{\text{overhead}}$$
&lt;p>where:&lt;/p>
&lt;ul>
&lt;li>$V_{\text{model}}$ is the size of the weights: for a model of $P$ parameters in a format of $b$ bytes/parameter, $V_{\text{model}} = P \cdot b$. Llama 70B BF16 = $70 \times 10^9 \times 2 = 140$ GB. Under tensor parallel TP=4, each GPU carries $140 / 4 = 35$ GB.&lt;/li>
&lt;li>$V_{\text{activations}}$ are the intermediate buffers of the forward pass. For vLLM with a reasonable batch, between 2 and 6 GB per GPU depending on batch size and maximum length.&lt;/li>
&lt;li>$V_{\text{overhead}}$ is the CUDA context, NCCL buffers, the PagedAttention pool, reserved paged blocks. 2–4 GB typical.&lt;/li>
&lt;/ul>
&lt;p>The KV cache budget per GPU is what is left over. For an H100 SXM 80 GB with Llama 70B TP=4 BF16:&lt;/p>
$$V_{\text{kv}} = 80 - 35 - 4 - 3 = 38 \text{ GB per GPU} = 152 \text{ GB aggregated over TP=4}$$
&lt;p>The KV cache cost per token for a model with $L$ layers, $H_{\text{kv}}$ KV heads (GQA), per-head dimension $d_h$, in a format of $b$ bytes:&lt;/p>
$$\text{kv per token} = 2 \cdot L \cdot H_{\text{kv}} \cdot d_h \cdot b$$
&lt;p>The factor of 2 is because both K and V are stored. For Llama 70B (L=80, $H_{\text{kv}}$=8 with GQA, $d_h$=128, BF16 = 2 bytes):&lt;/p>
$$\text{kv per token} = 2 \cdot 80 \cdot 8 \cdot 128 \cdot 2 = 327,680 \text{ bytes} = 320 \text{ KB/token}$$
&lt;p>And the maximum concurrency at average context $C$:&lt;/p>
$$N_{\text{max}} = \frac{V_{\text{kv}}}{C \cdot \text{kv per token}}$$
&lt;p>With an aggregated $V_{\text{kv}}$ of 152 GB and an average context of 1,500 tokens (800 prompt + 700 generated at the worst moment of the conversation):&lt;/p>
$$N_{\text{max}} = \frac{152 \times 10^9}{1,500 \cdot 320 \times 10^3} \approx 316 \text{ concurrent requests}$$
&lt;p>This is the &lt;strong>physical ceiling&lt;/strong> of concurrency for that replica. It is not what you are going to use; it is what you &lt;strong>cannot exceed&lt;/strong> without OOM. The operational number sits well below it (head-room for spikes).&lt;/p>
&lt;h3 id="time-budget">Time budget&lt;/h3>
&lt;p>Two sub-calculations come in here: decode (memory-bound) and prefill (compute-bound).&lt;/p>
&lt;p>&lt;strong>Decode TPOT.&lt;/strong> For every token generated, the model weights (the ones relevant to that request) have to be walked through and the accumulated KV cache has to be read. The bottleneck is HBM bandwidth. For a GPU with bandwidth $B$ GB/s and a model of $V_{\text{model per gpu}}$ GB of weights:&lt;/p>
$$\text{tpot}_{\text{theoretical}} \approx \frac{V_{\text{model per gpu}}}{B}$$
&lt;p>For an H100 SXM with HBM3 at 3.35 TB/s and Llama 70B TP=4 BF16 (35 GB/GPU):&lt;/p>
$$\text{tpot}_{\text{theoretical}} \approx \frac{35}{3,350} \approx 10.4 \text{ ms/token}$$
&lt;p>This is the &lt;strong>best theoretical case&lt;/strong> with batch=1 and 100 % HBM efficiency. In practice vLLM on H100 with Llama 70B TP=4 reaches 12–18 ms/token at low batch and 30–45 ms/token at high batch (at concurrency 32, tokens compete for the shared HBM). The defensible operational number: &lt;strong>35 ms/token&lt;/strong> at concurrency 24–32.&lt;/p>
&lt;p>&lt;strong>Prefill throughput.&lt;/strong> Prefill processes N prompt tokens in a single forward pass. It is compute-bound: the bottleneck is FLOPs. For an H100 SXM with 989 sustained BF16 TFLOPs and Llama 70B (each forward pass costs roughly $2 \cdot P \cdot N$ FLOPs per sequence of length N):&lt;/p>
$$\text{prefill tps} = \frac{4 \cdot \text{TFLOPs} \cdot \eta}{2 \cdot P} = \frac{4 \cdot 989 \times 10^{12} \cdot 0.5}{2 \cdot 70 \times 10^9} \approx 14,000 \text{ tokens/s}$$
&lt;p>(the factor of 4 is the GPUs in TP, $\eta$ is real efficiency between 0.4 and 0.6 on H100). An 800-token prompt takes this long in prefill:&lt;/p>
$$\text{prefill time} = \frac{800}{14,000} \approx 57 \text{ ms}$$
&lt;p>Adding a typical queue of 100–300 ms at high concurrency, &lt;strong>TTFT P95 ≈ 350–500 ms&lt;/strong> for that profile. Well below the 1.5 s target; there is margin.&lt;/p>
&lt;h3 id="the-crossing">The crossing&lt;/h3>
&lt;p>The real operational concurrency $N_{\text{op}}$ is the minimum of &lt;strong>the VRAM ceiling&lt;/strong>, the concurrency at which &lt;strong>TPOT starts to degrade&lt;/strong> past the SLO, and the concurrency at which &lt;strong>TTFT starts to degrade&lt;/strong> past the SLO (prefill queue). For the example:&lt;/p>
&lt;ul>
&lt;li>VRAM ceiling: 316.&lt;/li>
&lt;li>TPOT degrades to 80 ms (SLO) at around concurrency ~80–100 (measured empirically with a benchmark, not a closed formula).&lt;/li>
&lt;li>TTFT degrades to 1.5 s at around concurrency ~40–60 because of the prefill queue.&lt;/li>
&lt;/ul>
&lt;p>The replica&amp;rsquo;s operational concurrency is ~50. Applying 25 % head-room for spikes and rebalancing, &lt;strong>target concurrency per replica ≈ 35–40&lt;/strong>.&lt;/p>
&lt;h2 id="step-by-step-worksheet-llama-70b-bf16-on-4h100-sxm">Step-by-step worksheet: Llama 70B BF16 on 4×H100 SXM&lt;/h2>
&lt;p>The exercise&amp;rsquo;s input:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>SLO&lt;/strong>: TTFT P95 ≤ 1.5 s; TPOT P95 ≤ 60 ms; &lt;strong>200 sustained RPS&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Workload&lt;/strong>: prompt P50=600, P95=1,200, P99=2,500; output P50=180, P95=500, P99=900. Average prompt 800, output 250.&lt;/li>
&lt;li>&lt;strong>Generic hardware&lt;/strong>: 4×H100 SXM 80 GB with NVLink, vLLM v1 engine, tensor parallel 4, BF16.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Step 1 — VRAM per GPU.&lt;/strong> Weights 35 GB, activations 4 GB, overhead 3 GB → KV budget 38 GB/GPU = 152 GB aggregated. KV/token for Llama 70B GQA = 320 KB. Ceiling of live tokens in cache: $152 \times 10^9 / 320 \times 10^3 \approx 475,000$ tokens. At the operational average context (800 prompt + 200 already generated = 1,000 live tokens per request), concurrency ceiling $\approx 475$.&lt;/p>
&lt;p>&lt;strong>Step 2 — average duration of a request.&lt;/strong> Prefill 800 tokens / 14,000 tps = 57 ms. Decode 250 tokens × 35 ms/token = 8,750 ms. Total $\approx 8.8$ s per request.&lt;/p>
&lt;p>&lt;strong>Step 3 — replica throughput.&lt;/strong> If the replica sustains operational concurrency 40 and each request lasts 8.8 s, the replica delivers roughly $40 / 8.8 \approx 4.5$ requests/s in steady state.&lt;/p>
&lt;p>&lt;strong>Step 4 — number of replicas.&lt;/strong> For a 200 RPS target: $200 / 4.5 \approx 45$ replicas. That is 45 × 4 = 180 GPUs. Too much: this sizing does not work because the cost per request is high.&lt;/p>
&lt;p>&lt;strong>Step 5 — review the levers.&lt;/strong> Before buying more hardware, there are three levers to explore, in this order:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Quantisation.&lt;/strong> Dropping to FP8 reduces weights to 17.5 GB/GPU (leaving more VRAM for KV cache → more concurrency), roughly doubles decode tokens/s (HBM saturated by half), and degrades MMLU quality typically by 0.5–1.5 points on models like Llama 70B. Rewriting the calculation in FP8: TPOT drops to ~18 ms, total time per request to 4.7 s, RPS per replica rises to ~8.5, &lt;strong>replicas needed ≈ 24, equivalent to 96 GPUs&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Speculative decoding.&lt;/strong> With a small drafter and 60–70 % acceptance, effective TPOT falls 30–40 %. RPS per replica rises to ~12, &lt;strong>replicas ≈ 17 = 68 GPUs&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Disaggregated serving.&lt;/strong> Separating prefill workers and decode workers lets each be scaled to the real mix of the workload (see &lt;a href="https://blog.lo0.es/en/posts/disaggregated-serving-prefill-decode-specialised-pods/">Disaggregated serving&lt;/a>). It usually shaves off another 20–40 % under asymmetric workloads.&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Step 6 — recommended sizing.&lt;/strong> For the example, with FP8 + speculative decoding and 25 % head-room: &lt;strong>20 vLLM replicas at TP=4 over 80 H100 SXM&lt;/strong>. If the team does not want to depend on aggressive quantisation (pure BF16 for maximum fidelity), the calculation rises to &lt;strong>30 replicas = 120 GPUs&lt;/strong> and forces a renegotiation of the SLO or the budget.&lt;/p>
&lt;p>&lt;strong>Step 7 — write down the assumptions.&lt;/strong> This is the part no valid sizing skips. In the team&amp;rsquo;s repo, next to the calculation:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># sizing/llama70b-prod.yaml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">fecha&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="ld">2026-06-01&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">slo&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ttft_p95_ms&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1500&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tpot_p95_ms&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">60&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">rps_target&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">200&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">workload&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">prompt_tokens_p50&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">600&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">prompt_tokens_p95&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1200&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">output_tokens_p50&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">180&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">output_tokens_p95&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">500&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">asunto&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">chat productivo con RAG ligero&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">modelo&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">arquitectura&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llama-70b-instruct&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">formato_pesos&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">fp8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">motor&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">vllm-v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">hardware&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">H100-SXM-80GB&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">topologia&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">TP=4 con NVLink intra-nodo&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">red_inter_replica&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">25&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">GbE&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">optimizaciones&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">paged_attention&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">chunked_prefill&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">speculative_decoding (drafter llama-1.1b, aceptación esperada 65%)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">asunciones_criticas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">utilizacion_hbm_eficiente&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.55&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">head_room_pico_sobre_p95&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.25&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">aceptacion_speculative_min&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.55&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">plan_validacion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">benchmark vllm bench serve antes de procurement&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">canary 10% durante 7 días post-deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Without this YAML, the calculation is not reproducible a month later.&lt;/p>
&lt;h2 id="moe-case-mixtral-822b-141-b-total-39-b-active">MoE case: Mixtral 8×22B (~141 B total, 39 B active)&lt;/h2>
&lt;p>MoEs change the calculation along one key dimension: the total weights are large but the active weights per token are small. For Mixtral 8×22B with top-2 routing:&lt;/p>
&lt;ul>
&lt;li>Weight VRAM: $141 \times 2 = 282$ GB BF16. With TP=4 → 70 GB/GPU. It does not fit in an H100 80 GB alongside KV cache + activations. You need TP=8 (~35 GB/GPU) or FP8 with TP=4 (~35 GB/GPU).&lt;/li>
&lt;li>Decode TPOT: dominated by the weights read per token, which are $\sim 39 / 8 \cdot 2 \approx 9.75$ GB/GPU with TP=4 (one top-2 expert per token, divided across 4 GPUs). On an H100 with HBM at 3.35 TB/s, &lt;strong>theoretical TPOT ≈ 3 ms/token&lt;/strong>. In practice, 10–20 ms at reasonable concurrency.&lt;/li>
&lt;li>Prefill: similar to the dense model of the active weights, ~39 B FLOPs/token.&lt;/li>
&lt;/ul>
&lt;p>MoE sizing usually delivers more RPS per GPU than an equivalent dense model: the low cost per token compensates for the extra VRAM. See &lt;a href="https://blog.lo0.es/en/posts/moe-inference-fundamentals-expert-parallel-deepseek-economics/">MoE inference&lt;/a> for the detail of routing and why a high batch is decisive so that each expert sees enough tokens.&lt;/p>
&lt;h2 id="sensitivity-table-context-and-quantisation">Sensitivity table: context and quantisation&lt;/h2>
&lt;p>For Llama 70B on 4×H100 SXM (TP=4), operational concurrency per replica with an SLO of TTFT 1.5 s / TPOT 60 ms:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Average context&lt;/th>
&lt;th>BF16&lt;/th>
&lt;th>FP8&lt;/th>
&lt;th>INT4 (AWQ)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>500 tokens&lt;/td>
&lt;td>55&lt;/td>
&lt;td>110&lt;/td>
&lt;td>180&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>1,000 tokens&lt;/td>
&lt;td>40&lt;/td>
&lt;td>80&lt;/td>
&lt;td>130&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2,000 tokens&lt;/td>
&lt;td>24&lt;/td>
&lt;td>50&lt;/td>
&lt;td>85&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4,000 tokens&lt;/td>
&lt;td>12&lt;/td>
&lt;td>26&lt;/td>
&lt;td>48&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>8,000 tokens&lt;/td>
&lt;td>6&lt;/td>
&lt;td>13&lt;/td>
&lt;td>25&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Approximate numbers from public vLLM benchmarks as of June 2026, with ±20 % variation depending on engine version and the headroom adopted. To validate on your own hardware: &lt;code>vllm bench serve&lt;/code> with your profile of real prompts.&lt;/p>
&lt;h2 id="the-five-habitual-traps">The five habitual traps&lt;/h2>
&lt;p>&lt;strong>Trap 1 — confusing the mean with P95.&lt;/strong> Average throughput over an hour may be 50 RPS while the 5-minute peak reaches 180 RPS. Sizing against the mean guarantees breaking the SLO at every peak. Rule: size against the hourly P95, with 20–30 % head-room over P95.&lt;/p>
&lt;p>&lt;strong>Trap 2 — not measuring the real prefill/decode split.&lt;/strong> A &amp;ldquo;RAG with short answers&amp;rdquo; workload spends 70–80 % of GPU time in prefill; a &amp;ldquo;writing assistant generating essays&amp;rdquo; spends 80 % in decode. The useful optimisations (chunked prefill vs speculative decoding) change radically. Without measuring it, you buy badly balanced hardware.&lt;/p>
&lt;p>&lt;strong>Trap 3 — sizing with no head-room for retraining or rollback.&lt;/strong> The production cluster is not just the inference engine: there is a re-embedding batch when the embeddings model changes, continuous canary evals (see &lt;a href="https://blog.lo0.es/en/posts/canary-blue-green-shadow-llm-models/">Canary, blue-green and shadow&lt;/a>), light fine-tuning, hot stand-by for rollback. Reserve 15–25 % of capacity for those non-negotiable workloads.&lt;/p>
&lt;p>&lt;strong>Trap 4 — &amp;ldquo;GPU at 100 % SM utilization&amp;rdquo; as a target.&lt;/strong> SM occupancy of 95 % with saturated HBM produces the same throughput as SM at 60 % with saturated HBM. The bottleneck in decode is the HBM. Optimising for &amp;ldquo;GPU usage 100 %&amp;rdquo; without looking at HBM utilisation and arithmetic intensity makes you spend more on GPU without gaining throughput. See &lt;a href="https://blog.lo0.es/en/posts/gpu-observability-llm-inference-twelve-dcgm-vllm-metrics/">GPU observability for LLM inference&lt;/a> for which metrics to actually watch.&lt;/p>
&lt;p>&lt;strong>Trap 5 — not documenting the assumptions.&lt;/strong> A sizing with no reproducible YAML (workload, model, engine, head-room, critical assumptions) leaves the team with no way of knowing what changed when the cluster stops meeting the SLO six months later. Documenting is cheap; losing a quarter to debugging is not.&lt;/p>
&lt;h2 id="applied-to-typical-on-premise-hardware">Applied to typical on-premise hardware&lt;/h2>
&lt;p>For a generic cluster of &lt;strong>4×H100 SXM 80 GB with intra-node NVLink and 25 GbE between nodes&lt;/strong>, the recurring configurations in May 2026 are:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Model&lt;/th>
&lt;th>Format&lt;/th>
&lt;th>TP&lt;/th>
&lt;th>Replicas that fit&lt;/th>
&lt;th>Typical RPS per node (ctx 1K)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Llama 8B&lt;/td>
&lt;td>BF16&lt;/td>
&lt;td>1&lt;/td>
&lt;td>4 (one per GPU)&lt;/td>
&lt;td>240–320&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Llama 8B&lt;/td>
&lt;td>FP8&lt;/td>
&lt;td>1&lt;/td>
&lt;td>4&lt;/td>
&lt;td>450–600&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Llama 70B&lt;/td>
&lt;td>BF16&lt;/td>
&lt;td>4&lt;/td>
&lt;td>1&lt;/td>
&lt;td>30–45&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Llama 70B&lt;/td>
&lt;td>FP8&lt;/td>
&lt;td>4&lt;/td>
&lt;td>1&lt;/td>
&lt;td>60–90&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Llama 70B&lt;/td>
&lt;td>INT4 AWQ&lt;/td>
&lt;td>2&lt;/td>
&lt;td>2&lt;/td>
&lt;td>90–130&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Mixtral 8×22B&lt;/td>
&lt;td>FP8&lt;/td>
&lt;td>4&lt;/td>
&lt;td>1&lt;/td>
&lt;td>90–140&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Qwen 72B&lt;/td>
&lt;td>BF16&lt;/td>
&lt;td>4&lt;/td>
&lt;td>1&lt;/td>
&lt;td>28–42&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>These numbers are &lt;strong>orders of magnitude to start the conversation&lt;/strong>, not commitments. The definitive sizing is validated with &lt;code>vllm bench serve&lt;/code> or &lt;code>genai-perf&lt;/code> (NVIDIA) using the customer&amp;rsquo;s real prompt/output profile. The prefill/decode asymmetry of each case&amp;rsquo;s workload can move these numbers 30–50 % up or down.&lt;/p>
&lt;p>For clusters of 8×H100 SXM (typical of DGX servers or equivalent replicas), the options open up to TP=8 for 405B-class models or multi-replica TP=2 for 70B models with greater density. The metric that decides is always the same: tokens meeting SLO per kW and per euro of amortised hardware.&lt;/p>
&lt;h2 id="how-the-sizing-is-validated-before-buying">How the sizing is validated before buying&lt;/h2>
&lt;p>The spreadsheet sizing is the first half. The second is the validation benchmark.&lt;/p>
&lt;p>&lt;strong>Stage 1 — back-of-the-envelope sizing.&lt;/strong> This post&amp;rsquo;s formulas applied to the SLO and the expected workload. Output: an approximate number of replicas and a topology.&lt;/p>
&lt;p>&lt;strong>Stage 2 — synthetic micro-benchmark.&lt;/strong> On a borrowed GPU or one rented by the day, bring up the engine with the chosen model and run &lt;code>vllm bench serve&lt;/code> with prompts of representative lengths. Validate TPOT, prefill TPS and the concurrency ceiling. Calibrate the HBM efficiency factor ($\eta$) used in the formulas.&lt;/p>
&lt;p>&lt;strong>Stage 3 — load test with realistic traffic.&lt;/strong> Generate traffic following the real distribution of the customer&amp;rsquo;s workload (not Poisson, not constant: the real trace). Measure P50/P95/P99 of TTFT, TPOT, throughput. Confirm the head-room.&lt;/p>
&lt;p>&lt;strong>Stage 4 — canary in production.&lt;/strong> With the cluster sized, route 5–10 % of real traffic for 7–14 days before closing the procurement of additional hardware. See &lt;a href="https://blog.lo0.es/en/posts/canary-blue-green-shadow-llm-models/">Canary, blue-green and shadow&lt;/a> for the mechanics.&lt;/p>
&lt;p>Jumping from Stage 1 to full procurement is the most frequent cause of a cluster that is 40 % oversized and 60 % undersized at the same time, in different regions of the workload. Four weeks of validation done well save four months of refactoring.&lt;/p>
&lt;h2 id="what-we-have-not-covered-upcoming-articles">What we have not covered (upcoming articles)&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>The observability metrics&lt;/strong> that close the sizing loop in production, see &lt;a href="https://blog.lo0.es/en/posts/gpu-observability-llm-inference-twelve-dcgm-vllm-metrics/">GPU observability for LLM inference&lt;/a>.&lt;/li>
&lt;li>Autoscaling that adjusts replicas to the real traffic curve, see &lt;a href="https://blog.lo0.es/en/posts/llm-inference-autoscaling-kubernetes-hpa-keda/">Autoscaling LLM on Kubernetes&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Detailed cost accounting&lt;/strong> per tenant (showback / chargeback) over the sized hardware.&lt;/li>
&lt;li>&lt;strong>Sizing for continuous fine-tuning&lt;/strong> (PEFT and light training) that shares a cluster with inference.&lt;/li>
&lt;/ul>
&lt;h2 id="see-also">See also&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/finops-multi-tenancy-gpu-cluster-who-pays/">FinOps and multi-tenancy of the GPU cluster: who pays for what&lt;/a> — translating the sizing into €/token and attributing cost per team.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/kv-cache-working-memory-llm-inference/">KV cache: the working memory that holds up LLM inference&lt;/a> — the component that dominates the VRAM budget.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/continuous-batching-orca-vllm-chunked-prefill-goodput/">Continuous batching&lt;/a> — what defines the effective utilisation of the compute and the goodput metric.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/disaggregated-serving-prefill-decode-specialised-pods/">Disaggregated prefill/decode serving&lt;/a> — an advanced lever for asymmetric workloads.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/moe-inference-fundamentals-expert-parallel-deepseek-economics/">MoE inference&lt;/a> — how the sums change with MoE models.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/quantization-llm-inference-fp8-int4-gguf/">Quantisation for inference&lt;/a> — what each format costs and what it saves.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/anatomy-on-premise-llm-inference-stack-seven-layers/">Seven layers of the on-premise LLM inference stack&lt;/a> — the pieces the sizing takes for granted.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/mixed-nvidia-intel-environments-llm-inference/">Mixed NVIDIA + Intel environments for LLM inference&lt;/a> — the sizing closes better once heterogeneity is accepted: embeddings and reranker on Intel Xeon AMX free up H100s for the large LLM, without buying more GPU.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/numa-hugepages-cpu-isolation-gpu-waits-kernel/">NUMA, hugepages and CPU isolation&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/cpu-memory-topology-manager-rke2/">RKE2 resource managers&lt;/a> — why the sizing comes to be reasoned per NUMA node rather than per node: you have to discount the reserved housekeeping cores and check that the pod fits on a single NUMA &amp;ldquo;table&amp;rdquo;.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/full-tco-on-premise-gpu-cluster-capex-gpu-hour-break-even/">TCO of the on-premise GPU cluster: amortisation, energy and infrastructure&lt;/a> — the €/GPU-hour that closes the sizing&amp;rsquo;s economic model: once you know how many GPUs you need, here is the real cost of owning them.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/slo-to-number-of-gpus-sizing-justifying-inference-hardware/">Sizing and justifying the investment in GPU&lt;/a> — the full roadmap for turning this sizing into an investment proposal defensible before management: ROI, break-even and sensitivity analysis.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/sizing-agents-decode-bottleneck/">Sizing for agents&lt;/a> — the same method with the inputs changed, when the caller is an agent and not a person.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="references">References&lt;/h2>
&lt;ul>
&lt;li>Kwon et al. — &lt;em>vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention&lt;/em> (SOSP 2023).&lt;/li>
&lt;li>Zhong et al. — &lt;em>DistServe: Disaggregating Prefill and Decoding for Goodput-optimized LLM Serving&lt;/em> (OSDI 2024).&lt;/li>
&lt;li>Agrawal et al. — &lt;em>Taming Throughput-Latency Tradeoff in LLM Inference with Sarathi-Serve&lt;/em> (OSDI 2024).&lt;/li>
&lt;li>NVIDIA — &lt;em>H100 Tensor Core GPU Architecture Whitepaper&lt;/em> (HBM3 memory, bandwidth, sustained FLOPs).&lt;/li>
&lt;li>vLLM project — &lt;code>vllm bench serve&lt;/code> reference (benchmarking CLI included in the repo).&lt;/li>
&lt;li>NVIDIA — &lt;code>genai-perf&lt;/code> (official tool for benchmarking LLM services).&lt;/li>
&lt;/ul></description></item></channel></rss>