Two workloads, two benchmarks of ours, and one that is not ours. Every number here was measured on a described host with a published harness, and the caveats travel with the figures.
Equal work in the first two: llmbridge and LiteLLM each do the full OpenAI↔Anthropic translation against the same backend. LiteLLM is a full router/SDK and does far more than translate; we compare only the gateway hop both perform, never the model's own latency. The third is an external harness that runs nine gateways through one methodology we did not write. At the end, one request's anatomy, where every microsecond goes.
Figures on this page were measured over plain HTTP to a local mock backend. TLS and WAN latency are excluded on purpose so the number isolates gateway overhead. The LiteLLM head-to-heads pin LiteLLM 1.95.0, the release they were measured against; the throughput ceiling is the median of 3 cold-boot runs (87k best), the streaming figures the median of 3 as well. A current LiteLLM (1.99) cuts its own added p99 at 100 RPS from 87 ms to 24–30 ms, so read the ratio as roughly 300× against today’s release and 1,000× against the pinned one. Every release is regression-checked against these paths. Re-run on every tagged release, see BENCHMARKS.md to reproduce.
The first two benchmarks below measure different units of work and their numbers are not interchangeable. A streaming request holds one connection for an entire generation, so "requests per second" is not its axis. A non-streaming request delivers one payload, so "tokens per second" says nothing about it. We report them separately for that reason.
Open-loop, coordinated-omission-corrected load generator against a 200 ms mock backend. One worker each.
llmbridge's ceiling here (~84k RPS) is set by the worker's own CPU on its single thread. llmbridge is single-threaded, so one core is its hard ceiling, and at saturation that thread is 87–92% busy, i.e. out of headroom. (The machine reports ~95% idle only because one busy core is ~8% of 12 logical CPUs; reaching the rest needs --workers N.) Splitting that thread's own CPU time: ~89% kernel, ~7% llmbridge, the biggest kernel slice being the TCP stack at 32.7%, the price of being a TCP proxy. Thermally dependent: 87k cold, 82k at 85 °C. Everything runs over 127.0.0.1. Scaling past this ceiling is --workers N (shared-nothing, SO_REUSEPORT), which nearly doubles it per worker; a separate-host run is on the roadmap.
| RPS | llmbridge added p99 | LiteLLM added p99 | LiteLLM throughput |
|---|---|---|---|
| 100 | 0.080 ms | 87 ms | 100 / 100 ✓ |
| 1000 | 0.047 ms | 14,213 ms | 244 / 1000 (sat) |
| 5000 | 0.041 ms | 18,695 ms | 236 / 5000 (sat) |
Honest methodology: single Linux host (i7-9750H), mock + proxy + load generator co-located, single worker/thread each, plain HTTP, mock backend (the model's latency is excluded on purpose, to isolate gateway overhead). llmbridge is proxy-self-measured, and LiteLLM is client-measured (e2e − backend). The throughput ceiling on this box is the worker's own CPU, at saturation it burns 87–92% of one core, and perf puts ~89% of that in the kernel (32.7% in the TCP stack) against 6.7% in llmbridge's own code. So the ceiling is a single-thread limit, and the headroom is in kernel work per request, not in the translator. The figure is also thermally dependent (87k cold, 82k at 85 °C on this laptop). Fully reproducible. ./bench/run_headtohead.sh and ./bench/saturate.sh. A clean separate-host run is on the roadmap.
“Concurrent streams” means responses in flight at once through one gateway process. 512 streams is 512 simultaneous voice agents or chat replies, each receiving a token every 20 ms.
Both gateways translate the same Anthropic event stream into OpenAI chunks, at 50 tok/s per stream, swept over concurrency. Every number is taken by the same client-side instrument (neither gateway self-reports) and "added" latency is measured against a no-gateway control run at the same concurrency. Single run per concurrency level.
Every column here is what the gateway adds, not what the request took. The no-gateway control's time to first token is 30.7–30.8 ms at every concurrency (that floor is the mock provider's own think time); llmbridge measures 30.6–30.9 ms, i.e. the same number within ±0.2 ms of run-to-run noise, so it adds nothing measurable and absolute TTFT through it stays ~31 ms. LiteLLM holds at 16 streams, then queues. Delivery: llmbridge 99.93–100% of the achievable token stream, LiteLLM 4% at 512 streams. Its ceiling is roughly 1,100 tokens/s per worker regardless of offered load.
TTFT here is time to first token, not first byte: the harness stamps the arrival of the first SSE chunk that actually carries a token, skipping the response headers, so a provider (or gateway) cannot look fast by sending headers early.
| Concurrent streams | llmbridge added / token | LiteLLM added / token | TTFT added vs no gateway llmbridge / LiteLLM | Tokens delivered |
|---|---|---|---|---|
| 16 | 57 µs | 1.4 ms | +0.0 ms / +50 ms | 100.00% / 94% |
| 64 | 55 µs | 191 ms | +0.0 ms / +2.0 s | 99.98% / 40% |
| 256 | 86 µs | 602 ms | +0.0 ms / +10.2 s | 99.94% / 10% |
| 512 | 131 µs | > 2 s | +0.0 ms / +12.6 s | 99.93% / 4% |
512 is where the LiteLLM comparison stops, not where llmbridge does. Held at 16,384 simultaneous streams on one worker. 16,384 voice agents or chat replies in flight at once, 32,774 sockets open, and it delivers 99.96% of offered tokens with zero client-side failures, p50 36–48 µs and p99 under 0.6 ms, while consuming ~31% of a single CPU core and 189 MB of RAM. Eight independent load generators agree within 5%.
Pushed to 24,576 streams it still delivers
99.93% with zero failures, at 42–47% of one core and 272 MB
(p50 50–58 µs, p99 ~1.2 ms). That is not llmbridge's ceiling;
it is the test machine's: 49,152 of the host's 55,536 ephemeral ports are in use, so
measuring higher needs the load generator spread across multiple loopback addresses. We
claim no number above 24,576. Scale beyond one worker with --workers N.
Honest methodology: the provider stamps its own monotonic emission time inside every token, so added latency is arrival − emission, no clock sync, and no assumption about when a token should have arrived, which is what makes coordinated omission impossible here. LiteLLM gets a full unmeasured warm-up round (its cold start is severe), one worker each, order alternated per level. LiteLLM's per-token latency above 2 s exceeds our histogram's range, so we print "> 2 s" instead of a number that would look like a percentile but is really just the maximum. llmbridge never overflowed it. Single co-located host, plain HTTP; absolute tails are a dev-box upper bound. Reproduce: ./bench/run_stream_headtohead.sh, full method, harness and host configuration in BENCHMARKS.md.
The harness is public and MIT-licensed, written by Jakub A. Wąsek of ENTERPILOT, who publishes his own runs. Every gateway runs from its public Docker image, one at a time, against the same in-memory Go mock, with a no-gateway baseline: 20,000 requests per variant at concurrency 10, five trials in randomised order, six variants (chat, responses and messages, streamed and not), and a separate throughput sweep from 1 to 256 concurrent. Its unit of work is one request, so it sits beside A and never beside B.
| gateway | cores | chat p50 | above floor | chat/stream p50 | above floor | peak req/s | memory | req/s per CPU% |
|---|---|---|---|---|---|---|---|---|
| socat byte pipe, the floor | 2.17 | 0.06 ms | 0 | 0.27 ms | 0 | 43,973 | 5 MB | 157 |
| llmbridge v0.53.0 | 0.98 | 0.07 ms | 0.01 | 0.18 ms | at the floor | 40,677 | 32 MB | 354 |
| llmbridge, translating to Anthropic | 1.02 | 0.10 ms | 0.04 | 0.56 ms | 0.29 | 35,298 | 30 MB | 300 |
| GoModel 0.1.86 | 5.96 | 0.47 ms | 0.41 | 0.75 ms | 0.48 | 16,468 | 77 MB | 23 |
| Bifrost 2.0.0 | 7.90 | 0.80 ms | 0.74 | 2.77 ms | 2.50 | 10,043 | 493 MB | 11 |
| Portkey 1.15.2 | 1.20 | 7.56 ms | 7.50 | 27.60 ms | 27.33 | 1,232 | 198 MB | 10 |
| LiteLLM 1.99.1 | 7.05 | 10.77 ms | 10.71 | 46.06 ms | 45.79 | 880 | 9,528 MB | 1 |
| TensorZero 2026.6.0 | 0.17 | 41.74 ms | 41.68 | 41.03 ms | 40.76 | 6,834 | 132 MB | 16 |
| OmniRoute 3.8.50 | 1.08 | 172.01 ms | 171.95 | 207.37 ms | 207.10 | 58 | 929 MB | 0.4 |
How to read it. Added p50 is over the harness’s own no-gateway baseline. That baseline is one bridge traversal and every gateway is two, so each figure carries one hop that belongs to the topology. The socat byte pipe parses nothing and measures exactly that hop, and “above floor” subtracts it. llmbridge’s streaming row measured under the pipe by 0.09 ms, which is noise around zero and reads as at the floor, never as faster than copying bytes. The cores column is not optional: GoModel and Bifrost take every core through the Go runtime and LiteLLM runs one worker per core, so throughput quoted without cores flatters them and understates a single-threaded gateway by about an order of magnitude. The last column is throughput per percent of CPU. Coverage: llmbridge serves four of the six variants, refusing the Anthropic messages pair because that translation is not built, and the translating arm refuses responses. A refusal is not a failure. LiteLLM completed 57,690 of 100,000 streamed chat requests inside the window, and Bifrost’s messages/stream failed outright. TensorZero and OmniRoute are configuration problems, not measurements of the software, and belong in no headline. Two divergences from the published harness, stated because they matter: Docker’s default seccomp filter was off for every gateway, since it blocks io_uring and would have put llmbridge on epoll, and the host is a 12-CPU laptop against the 2-vCPU c7i.large behind ENTERPILOT’s tables, so these rows compare within this table and never with theirs. One llmbridge worker throughout. bench/run_enterpilot.sh in the repository reproduces it, and every variant with the resolved image digests is committed as data next to it.
Seven monotonic stamps bound every request. The gold spans are llmbridge, and with --timing-headers the gateway reports each interval on every response. Measured 2026-08-01 against the live Anthropic API: of an 815 ms time to first token, llmbridge was 0.045 ms.
x-llmbridge-gateway-us
connection setup: TCP and TLS to the provider, paid once, 0 when pooled. x-llmbridge-connect-us
before t0: the client’s own handshakes and upload. Not ours, not counted.
provider and network: nearly all of the request. x-llmbridge-upstream-us
TLS: cipher on send, decipher on receive, counted inside our spans.
Not to scale: drawn to scale, every span but the provider’s would be a hairline. Streaming is identical through t3; t4 is the response head, and t5 to t6 repeat per chunk. Every stamp, defined: LATENCY.md.