Latency, throughput and tokens/second

How do you measure the actual performance of Large Language Models in an objective and reproducible way?

Introduction

Measuring the speed of Large Language Models (LLMs) differs fundamentally from traditional web applications. While a web server returns a complete HTTP response in milliseconds, LLMs generate text token by token in an iterative process. This requires specialized metrics and a careful measurement setup to compare apples to apples.

The Core Metrics

To accurately map the performance of an LLM endpoint, three fundamental pillars are examined:

TTFT (Time to First Token)

The time from sending the prompt to receiving the very first generated token. This determines how 'responsive' an application feels to the end user.

Tokens per Second (Generation)

The speed at which the autoregressive loop produces new tokens after the first token. This provides insight into the computing power of the underlying inference hardware.

Total Throughput

The total processed workload over time, expressed in total tokens (input + output) divided by the total processing time including network latency.

What affects speed?

Several factors at the hardware, model, and network level directly influence the measured performance:

Example Measurement Setup

For a fair and reproducible benchmark, it is necessary to control external variables. Below is a conceptual script to perform standardized measurements via an API.

import time
import requests

def benchmark_endpoint(api_url, payload, api_key, iterations=5):
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
results = []

for i in range(iterations):
start_time = time.perf_counter()
first_token_time = None
total_tokens = 0

response = requests.post(api_url, json=payload, headers=headers, stream=True)

for line in response.iter_lines():
if line:
if first_token_time is None:
first_token_time = time.perf_counter()
# Count tokens based on chunk structure (provider-specific)
total_tokens += 1

end_time = time.perf_counter()

ttft = first_token_time - start_time
total_duration = end_time - start_time
generation_time = total_duration - ttft
tokens_per_sec = total_tokens / generation_time if generation_time > 0 else 0

results.append({
"run": i + 1,
"ttft_sec": ttft,
"tokens_per_sec": tokens_per_sec
})

return results

Comparative Table

The table below structures the recorded measurements. Note: the values shown are placeholders and should be filled in based on actual, calibrated test runs.

Model & Configuration Input Tokens Output Tokens Avg. TTFT (s) Generation (tok/s)
[Model A - 8B - FP16] [Placeholder] [Placeholder] [Placeholder] [Placeholder]
[Model B - 70B - INT4] [Placeholder] [Placeholder] [Placeholder] [Placeholder]
[Model C - Serverless API] [Placeholder] [Placeholder] [Placeholder] [Placeholder]