AI Engineer World's Fair 2026

Are LLM Performance Benchmarks Reliable? — Ashok Chandrasekar & Jason Kramberger, Google

Read the talk

Are LLM Performance Benchmarks Reliable?

Ashok Chandrasekar and Jason Kramberger explain how a benchmark client can underdeliver load, inflate latency, and change the workload it claims to measure—and how InferencePerf makes those failures observable at production scale.

From a talk by Ashok Chandrasekar and Jason Kramberger

At a glance

Ideas worth remembering

  • Check delivered load before interpreting server performance: a requested 200-QPS run delivered only 38 QPS, while some single-process harnesses capped near 170 QPS on a larger machine.

  • An overwhelmed streaming-response collector can inflate measured latency. One test showed up to 58 seconds of client-induced delay.

  • Temperature, sampling, truncation, generation stopping, prefix-cache behavior, and multi-turn replay help define the workload. Dataset identity alone does not ensure comparable requests.

  • InferencePerf distributes execution across processes and reports planned-versus-actual timing alongside server metrics, exposing a harness that falls behind.

  • Use load sweeps and latency objectives to choose an operating point, then preserve the workload definition so comparisons can be repeated across runs and tools.

A results table does not tell you which experiment ran

A benchmark usually starts with a small set of inputs: a model, a number of prompts, input and output lengths, and a requested load. It returns input-token throughput, output-token throughput, time to first token, and time per output token. Ashok Chandrasekar and Jason Kramberger, Google engineers working on inference performance and co-maintaining InferencePerf, kept encountering a problem with these reassuring tables: they often could not reproduce other people’s results. The numbers could look plausible even when the harness had failed to run the intended experiment.

The benchmark ecosystem contains tools with different jobs:

  • Model-server benchmarks: Frameworks such as vLLM and SGLang include developer-oriented benchmarks, commonly Python scripts, for measuring their servers.
  • Competitive comparisons: MLPerf and Artificial Analysis are examples of tools used to compare chips and accelerators.
  • HTTP load tests: Locust and Grafana k6 focus on generating web traffic at high scale.
  • Production inference benchmarks: The focus here is the complete inference-serving stack, including the many servers and serving mechanisms working together.

A tool that measures one model server successfully may struggle to drive an entire fleet. The benchmark harness—the client that generates requests and collects responses—has its own capacity limits. Those limits affect both the traffic reaching the server and the measurements coming back.

0:210:47
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

0:12 · section reference included

Find the operating point with load sweeps and latency objectives

The production example is llm-d, a distributed inference framework. Online serving and batch workloads can run against an inference pool containing many model servers. Prefill/decode disaggregation and workload autoscaling add further complexity. A harness must generate enough traffic to exercise that larger system while preserving the characteristics of the workload customers will actually run.

One queries-per-second figure cannot identify the best operating point. A sweep through several loads lets a team compare a baseline with an optimized configuration and find where the server saturates. The aim is to use capacity efficiently and save costs, with accurate measurements at each load. 3:50

Latency objectives constrain that choice. A P90 time-to-first-token service-level objective asks whether the ninetieth-percentile wait for the first token stays within the target. A configuration may complete plenty of work while failing that objective. The sweep therefore needs to show both throughput and the latency experienced at each load.

Four recurring problems undermine these comparisons: inaccurate metrics, little visibility into the harness itself, runs that cannot be reproduced, and unsuitable datasets. Before interpreting a server’s saturation curve, the team needs to know whether the client maintained the requested load and whether the requests remained comparable across runs.

Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

2:41 · section reference included

Ask for 200 QPS, receive 38

Chandrasekar’s experiment makes the client problem concrete. A harness was asked to generate 200 queries per second, but on a small machine it delivered only 38 QPS. Moving to a much more powerful machine increased the achievable load, yet some single-process harnesses still capped near 170 QPS. The requested rate remained 200; changing the client machine changed the traffic the server actually received. 5:24

The explanation centers on Python’s global interpreter lock in the CPU-bound, single-process harnesses under discussion. CPU work within that process can be limited by one CPU even when the machine has several available. A larger machine does not necessarily let the process use all that capacity. Distributing the work across processes addresses this limit.

The damaging part is the silent shortfall. The harness can finish and print its results without warning that it missed the requested rate: “I ran it. These are the numbers.” A reader may interpret the table as the server’s behavior under 200 QPS, although the server received much less traffic. The configured load and the measured response no longer describe the same experiment.

The client can also manufacture a latency problem. Collecting many streaming token responses can overwhelm the harness and delay its handling of those streams. One test showed client-induced delay of up to 58 seconds, enough to make a healthy server appear bottlenecked. In a 1,000 QPS test against a simulated server intended to introduce no serving latency, a harness that could scale out instead showed very little latency. The simulated endpoint helps isolate delay introduced by the measurement client. 6:33

Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

5:24 · section reference included

A faster result may describe a different workload

Another shared benchmark claimed 20% better throughput. Inspection revealed that its harness had set temperature to zero, producing more deterministic outputs than the workload Chandrasekar was comparing it with, whose temperature was around 0.7. That advantage belonged to the differing test conditions. The example does not establish a general throughput penalty for nonzero temperature or isolate which part of generation caused the difference. 7:19

Even “same dataset” can conceal different requests. Two harnesses using the same ChatGPT dataset produced different input tokens because they sampled and truncated the data differently. Naming the dataset identified the source material, but the preparation rules determined what the model actually processed.

Several workload decisions need to be explicit:

  • Generation stopping: Whether the harness forces generation through to the end of the sequence affects the work requested.
  • Prefix-cache behavior: Prefix-cache rates help characterize the workload and the reuse it exercises.
  • Multi-turn replay: Conversation turns require a replay strategy; a collection of isolated prompts does not fully describe that scenario.
  • Sampling and truncation: Rules for selecting and shortening examples must accompany the dataset.

These failures invite the wrong diagnosis. Low throughput may come from insufficient client capacity, high latency from an overwhelmed stream collector, and an apparent improvement from changed generation settings. Server measurements become useful when the experiment also exposes these possible client and workload causes.

Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

7:19 · section reference included

Separate the request plan from execution—and measure the gap

Kramberger introduces InferencePerf as a community benchmarking project developed out of Kubernetes Working Group Serving. Its design combines declarative configuration, a multiprocess load generator, and client metrics reported alongside server metrics. The configuration describes the intended experiment; the telemetry helps determine whether the client carried it out. 8:46

The main process queues requests according to their planned execution times. The plan can follow a Poisson process, use a constant request rate, or maintain a constant number of concurrent requests. These options express different demands: a schedule of arriving requests or a target number of requests in flight. Multiple worker processes pull from the queue and execute the requests, spreading client work across processes. 9:52

How does the architecture expose a client that falls behind? The diagram traces two paths: requests move from the plan through the queue to workers, while execution timing joins server metrics in the reporting path. Workers observe when requests actually execute relative to their planned times. That comparison makes scheduling delay visible rather than letting it disappear into an apparently valid server result.

This supplies the missing observation in the 200-QPS example. The requested rate becomes a plan whose execution can be checked, instead of a setting readers must take on trust. In the comparison Kramberger presents, InferencePerf kept up at 5,000 QPS and reported that it kept up. That is a demonstrated result under the comparison’s conditions, rather than a capacity guarantee for every workload and client machine. 10:34

How it fits togetherFrom planned load to observed execution

Poisson arrivals, constant rate, or fixed concurrency.

One scheduler feeds multiple worker processes. Comparing planned and actual execution times exposes client lag; server metrics describe the system receiving the load.

Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

8:46 · section reference included

Share how data becomes requests

A minimal InferencePerf configuration can run a random dataset against an endpoint. More detailed configurations describe conversation replay, including input and output lengths and their distributions. Those distributions preserve variation in request sizes instead of reducing the workload to one fixed length. The extra controls serve a practical purpose: representing the traffic the inference stack is supposed to handle. 11:00

The published workload catalog extends this idea beyond a single configuration file. Its examples include multi-turn generation, tree of thought, agentic generation, and batch summarization. Each has a natural-language scenario definition and detailed configuration information. Generic descriptions accompany InferencePerf-specific configuration so other tools can express the same scenarios. 11:44

This addresses the earlier dataset mismatch at the level where it occurred. A dataset names the source material; a workload definition explains how that material becomes requests. Cross-tool comparisons need agreement about the scenario, sampling, and preparation. Giving two harnesses the same data does not by itself make them perform the same work.

Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

11:00 · section reference included

Prism shares results with their workload context

Prism, part of llm-d, provides a UI for sharing workloads and benchmark results. The closing example uses agentic code generation on TPUs with eight replicas. It compares combined optimizations with a baseline consisting of a simple Kubernetes service in front of multiple model-server replicas. 12:50

The optimized configuration achieves substantially higher throughput in the presented comparison, described as approaching hundreds of thousands of tokens per second. The explanation does not specify the optimization bundle or precise curve values, so the result illustrates a production-scale comparison rather than a recipe for reproducing that gain. Its role is to complete the progression: define the workload, generate observable load, compare serving configurations, and share the result.

The closing principles turn the earlier failures into requirements for a valid benchmark:

  • Client concurrency: The harness needs enough parallel execution capacity to generate production-scale load.
  • Client observability: Measurements must show whether it met the configured demand, including planned-versus-actual execution behavior.
  • Metric fidelity: Client and server measurements together help determine whether the scenario ran as intended and where delays occurred.
  • Representative randomness and data: Deterministic settings, stochastic variables, and datasets must reflect the workload being tested. Making a run easier to repeat is useful only if it still represents the intended demand. 14:02

InferencePerf supplies the load generation and measurement tool; llm-d supplies the production inference context; Prism shares benchmark results and workload definitions. The practical question behind all three is whether a reported number describes the traffic you intended to measure. Delivered load, client behavior, and workload preparation make that question answerable.

Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

12:50 · section reference included

Resources

Read the complete timestamped transcript
  1. 0:12

    Hi, everyone. Welcome to our talk on, um, Are LLM Performance Benchmarks Reliable?

  2. 0:21

    Little bit about us. I'm Ashok Chandrasekar. I'm a staff software engineer at Google. I work on inference performance evaluation and optimization, um, and I lead a couple of open source projects. One is called InferencePerf, uh, which is a benchmarking tool to do reliable performance benchmarks, and, uh, I'm also the SIG lead for, uh, llm-d SIG Benchmarking. llm-d is a distributed inference framework, um, that makes production scale inference possible.

  3. 0:47

    Hi, everyone. I'm Jason Kramberger. I'm a software engineer at Google. Uh, I'm also a co-maintainer of InferencePerf and a few of the sub-projects that Ashok brought up, uh, and I work on inference performance and benchmarking.

  4. 1:03

    Okay, let's get started. Um, let's look a little bit about the... how the benchmark ecosystem looks like, right? Uh, you have your model server frameworks. Uh, these are vLLM, SGLang, um, and other model servers, and all of these have some benchmark capability within them, right? These are primarily Python scripts and are developer-focused benchmarks to see how you can, uh, measure the performance of your model server itself. And then you have your competitive analysis tools. Uh, these are MLPerf, Semianalysis, uh, Artificial Analysis, and so on,

  5. 1:33

    right? Um, they mainly aim for, uh, competitive performance benchmarks to compare, like, chip and accelerator performance. Uh, and then you have your typical web benchmarks. Uh, these are like Locust, uh, Grafana k6, um, and so on. These mainly focus on, uh, high scale, uh, HTTP benchmarks, right? Uh, and then you have your, um, last segment, which is the production scale, uh, LLM benchmarks, right? These are to actually benchmark, uh, your production inference serving stack, and that is our focus today, right?

  6. 2:03

    We'll be focusing mainly on InferencePerf and how we solve this, uh, production scale benchmark problem.

  7. 2:11

    So if you have run a benchmark before, uh, it typically looks like this, right? Um, you have some sort of, uh, benchmark harness, uh, and then you specify what model you are benchmarking, um, the number of prompts you want to run, what is the input/output sequence length, uh, and the request rate or the load you want to send, right? Uh, and your output looks something, uh, like what is on the right. Uh, this is basically your, uh, input token throughput, output token throughput, some latency metrics, time to first token, time per output token, and so on.

  8. 2:41

    Um, so what are some issues with a simple benchmark like this? Right. So if you want to actually benchmark production scale workloads, um, here I have a llm-d, uh, inference stack as an example, right? Uh, you can have, uh, online serving, you can have batch workloads, and if you see the inference pool below, uh, there are, like, lot of, um, servers that are running, right? And then you have, like, uh, complex configurations like prefill decode disaggregation, um, and workload autoscaling, and other

  9. 3:11

    things that are going on under the hood, and usually the scale is much larger, right? So your, um, normal benchmark harnesses runs into issues when you try to benchmark a setup like this. And if you look at, like, the key characteristics of what we want out of a production scale benchmark, we need to be able to do high load, uh, which is limited in a lot of tools out there. We need to be able to simulate real-world workloads, right? Um, what use it is if it is just some synthetic workload that is not accurately representing, uh, what your customers are going to run.

  10. 3:41

    Uh, and then mo- metrics fidelity is very important, right? Are the metrics accurate, and how well they work?

  11. 3:50

    Uh, this is like, uh, the set of metrics that llm-d measures, uh, by default. Uh, I just pulled it from the, uh, website there. Uh, as you can see, it's not just like a single QPS that you're running, right? You are sweeping a, a list of, uh, various loads, and, uh, you try to measure what the baseline is, and what optimizations you are making, and what the difference there is. Um, you need to find the right point where the server gets saturated, uh, s- uh, so you know the right optimal, uh, point to run your servers on,

  12. 4:20

    uh, to maximize performance and to save costs. Um, and things like, uh, SLOs become more important, right? What is your, um, time to first token P90 SLO, and are you conforming to that SLO?

  13. 4:34

    So when you run, like, um, normal benchmark, like we saw before, what are some of the pitfalls that you run into, right? Uh, we have been run, uh, running benchmarks for a couple of years, so we run into all sort of, uh, different results that people share, and a lot of times we aren't able to reproduce the results, uh, that are shared by other people, right? So that is what motivated this talk. Um, so these four common, uh, things that we, uh, see as an issue, right? One is accurate, uh, metrics, and two, observability into your benchmark tool itself.

  14. 5:05

    Um, do you know if your benchmark harness is actually failing? Is it not able to maintain the load? Um, and three, reproducibility. Uh, there is some inherent, uh, randomness, uh, in, like, the datasets that you use, so how do you make sure it is reproducible? And four, the dataset quality itself.

  15. 5:24

    So this is an experiment we ran. Um, we asked, like, a different benchmark harness to generate two hundred QPS, and this was the result, right? Um, so a couple of things I want to point out. Um, Python has this, uh, global interpreter lock if you have been working with Python, you know that, which makes everything, uh, sort of single-threaded. So even when you have, like, a multi-CPU machine, a lot of times you are limited by, uh, the performance of a single CPU, uh, when you are CPU-bound especially, right? Uh, so this

  16. 5:54

    kind of shows a single-process, um, benchmark harness and a multiprocess harness, and how, um, the QPS you are able to achieve differs based on it, right? When you run with a really, uh, small chat code mission, you can see that even when you request two hundred QPS, you are only getting thirty-eight QPS. And then you give it a bigger machine, and then some of these, uh, single process harness, they cap out at, like, 170 QPS, right? This is a much more powerful machine. Um, but it is a problem because you ask for 200 QPS, and then you don't know whether it actually

  17. 6:24

    delivered it. It will just say, "I ran it. These are the numbers." So you think, okay, you ran 200 QPS, but in fact, you are... You have not.

  18. 6:33

    Uh, the other issue that comes out of it is the latency inflation, right? If your server is saying, "Okay, this is how much QPS I was able to run, and this was the accurate numbers," that is one thing. But if your, uh, uh, benchmark harness is actually inflating latency, right, because it's thrashing trying to collect all the streaming token requests. Um, in one of the tests, we noticed, like, uh, the delay was up to 58 seconds. So you might look at this and go, "Oh, my server is bottlenecked," right? It's not able to handle all the requests. But in fact, it's actually your benchmark client that is inflating the latency,

  19. 7:03

    right? Uh, we ran, like, 1000 QPS test. Uh, when your, when your benchmark harness is actually able to scale out, you can see there is very minimal latency, right? This is a, a simulated server, so there shouldn't be any latency at all.

  20. 7:19

    Um, and like I said, there are, like, other, uh, variables that go into it, right? In one of the benchmarks, um, someone shared, and they said, "Hey, we are getting 20% better throughput." Then we looked into it, and we found out the benchmark harness was setting the model temperature to zero, right? Which means your model outputs are a lot more deterministic, and it was able to, uh, churn out a higher throughput than what you would normally see in, like, a real workload, right? Where your model temperature is, uh, somewhere around 0.7. Um, another thing is, like, we used a, a ChatGPT

  21. 7:49

    dataset, the same dataset across two different benchmark harness, and they produce different input tokens, right? This is because they sample them differently, they truncate them, uh, differently. So as a user, you don't have insight into this, right? You run it, you trust the numbers it produces, but they are wildly different. Uh, and there is much more, right? Do you actually force it to generate, uh, till the end of sequence? Are you looking at prefix cache rates? How do you do multi-turn, uh, replay via benchmarks? And, uh, how it...

  22. 8:19

    How do you actually get high fidelity, uh, on the actual workload that would resemble your production workload, right?

  23. 8:28

    So the main thing I wanted to convey here is, like, a lot of times you diagnose it as, um, your server or inference stack problem, but in a lot of cases it could be your, uh, benchmark harness.

  24. 8:39

    So what is the solution to this? How do we actually do reproducible benchmarks? Jason here will take you over that.

  25. 8:46

    Cool. Thanks, Ashok. Uh, so yeah. How do you, how do you solve these problems? Uh, we pulled together InferencePerf, uh, the CNCF project spanned out of Kubernetes Working Group Serving, uh, to provide, like, a standardized place for us to work with the community and solve some of these issues together. Uh, it enables the ability to have, like, a

  26. 9:15

    user-defined declarative configuration, uh, that allows you to have clear re- reproducibility across runs. Uh, we also added a load generator, uh, that solves the GIL problem in Python, uh, across multiple processes, and reports those client metrics back along with server metrics to ensure that you have the highest metric fidelity, and you're able to actually observe when

  27. 9:45

    your tool is having an issue versus your system under test.

  28. 9:52

    So first, going over the load generator, uh, you see that the main process actually queues requests based off of the planned time that they need to execute, which is based off of your configuration. This may be in some Poisson process or constant rate or maintaining a constant number of concurrent requests. This request queue channel is then spread across multiple processes

  29. 10:23

    which pull and ensure that they execute with minimum overhead, but then also observability about when they execute versus their planned time.

  30. 10:34

    And you can see this working at scale. So this is a comparison across other tools, uh, some being the HTTP Scale tools like k6. Uh, but you see that even at 5,000 QPS, InferencePerf was able to keep up due to this architecture, and most importantly, actually report that it was able to keep up.

  31. 11:00

    Other portion is configuration. So earlier, Ashok showed a brief example of how you might simply run a benchmarking tool. And here on the left, you can see a simple example running a random dataset against an endpoint. But the actual configuration that we have in front of InferencePerf is very detailed with a lot of knobs that allow you to accurately, uh, test your configuration off of your workloads.

  32. 11:30

    You can see here on the right that this is, uh, configuration for a conversation replay, where you're able to configure not only, like, the input/output length, but their distributions, et cetera.

  33. 11:44

    And further, beyond just the ability to configure a single run, we've actually worked together to have a published set of some of these workloads and configuration of InferencePerf that are tied to state-of-the-art inference workloads. For example, here in the workload catalog that we've put out, you're able to access standard multi-turn, uh, generation, tree of thought, agentic generation,

  34. 12:15

    uh, as well as batch summarization and others. Each one of these has a simple definition, uh, kind of in natural language that allows you to understand what the scenario is. But beyond that, there's also pretty detailed configuration metrics, not only in InferencePerf's configuration, but in generic terms so that this can actually be shared across tools and have a place for standardization

  35. 12:44

    of these workloads.

  36. 12:50

    So kind of the culmination of these things, uh, leads us to actual results that we can clearly display. Uh, and here's a screenshot from Prism, which is a UI we have for sharing not only those workloads that I showed before, but also some benchmarking results. Uh, and Prism is a part of the llm-d project. Here you can see a benchmark result for the agentic code generation workload that we showed before

  37. 13:21

    on TPUs. Uh, these three lines you see here

  38. 13:27

    show you the difference between combined optimizations, is the green line, and a baseline that is just a simple Kubernetes service incentive in front of multiple model server replicas. It's important to note here is that this is at production scale with eight replicas, and you can see that the combined optimizations were measured to be much higher than the baseline, scaling into almost hundreds of

  39. 13:56

    thousands of tokens per second.

  40. 14:02

    So the takeaways, kind of the principles for benchmarking validity based off of the pitfalls that Ashok brought up earlier. At production scale, you need client concurrency, and you need observability into your client's behavior and its ability to meet your configuration. The metric fidelity allows you to actually observe your client's behavior as well as your system under test and understand that your scenario was accurately executed and

  41. 14:32

    your performance results were valid. The stochastic variables, uh, and non-determinism or determi-determinism that you set amongst your run needs to reflect your real world demands, uh, for your workload. And m-most importantly, your data sets do truly matter. Your workloads, uh, need to be as close to what you are intending to test as possible. And,

  42. 15:02

    uh, we have examples in the workload catalog. So here we have three links to some of the things that we've presented on here before. InferencePerf is our benchmarking tool, and there's the Git repo for it. llm-d is a project that we work under, and InferencePerf under it in llm-d Benchmark. Uh, llm-d is for production scale inference, and then llm-d Prism, which was that UI we showed for the benchmarking

  43. 15:32

    results, uh, and the workload catalog that defines some of these workloads.

  44. 15:41

    So that will answer questions after, but we appreciate your time.

  45. 15:46

    Thank you.