Benchmark results

View Source

Captured by scripts/bench_matrix.sh on 2026-05-20 at 1e8be80.

Hardware / runtime

  • CPU: 12th Gen Intel(R) Core(TM) i9-12900HX (24 threads)
  • Kernel: Linux 6.19.6-arch1-1 x86_64
  • OTP: 29
  • Loadgen: 3 runs/cell × 5s measure (2s warmup), 50 clients, loopback
  • Bench client: in-tree roadrunner_bench_client (h1 + h2)

Numbers are the median req/s across 3 runs. p50 / p99 shown is roadrunner's for that cell. Per-server p50 / p99 for cowboy and elli land in /tmp/bench_results.csv after a matrix run if you need to diff alternative servers.

Re-run locally with:

./scripts/bench_matrix.sh

Override defaults via env: RUNS=5 DURATION=10 ./scripts/bench_matrix.sh. Set SKIP_BENCH=1 to regenerate the CSV / MD from the existing /tmp/bench_matrix.log without re-running the bench.

HTTP/1.1

scenarioroadrunnercowboyellirr p50 / p99
hello307 k201 k299 k112 µs / 1.4 ms
json299 k189 k304 k112 µs / 1.5 ms
echo304 k162 k282 k116 µs / 1.2 ms
headers_heavy257 k141 k253 k134 µs / 1.8 ms
large_response124 k98 k123 k310 µs / 2.7 ms
multi_request_body262 k125 k274 k134 µs / 1.5 ms
varied_paths_router290 k175 k118 µs / 1.5 ms
post_4kb_form193 k98 k199 µs / 1.5 ms
large_post_streaming20 k6.9 k2.5 ms / 5.7 ms
pipelined_h1580 k371 k4.8 k68 µs / 615 µs
websocket_msg_throughput232 k179 k149 µs / 2.0 ms
gzip_response138 k111 k286 µs / 2.2 ms

HTTP/2

scenarioroadrunnercowboyellirr p50 / p99
hello167 k163 k219 µs / 2.5 ms
json168 k153 k226 µs / 2.3 ms
echo164 k112 k235 µs / 2.2 ms
headers_heavy161 k90 k236 µs / 2.5 ms
multi_request_body140 k28 k279 µs / 2.4 ms
multi_stream_h2351 k335 k125 µs / 374 µs
streaming_response62 k61 k640 µs / 4.1 ms

Notes / known gaps

  • large_response is listed h1-only here. The h2 cell errored on 64 KB single-stream responses against both servers, which is a flow-control interaction in the test client and not a server-side bug.
  • pipelined_h1 elli: elli's keep-alive path doesn't pipeline; the elli column reflects per-request RTT, not pipelining.
  • websocket_msg_throughput is roadrunner + cowboy only; the elli fixture has no WebSocket support.
  • The wider set of scenarios (connection-shape storms, TLS handshake throughput, the HttpArena fixtures, etc.) is runnable ad-hoc via ./scripts/bench.escript --scenarios <name>. The headline matrix here mirrors ?MAIN_SCENARIOS in scripts/bench.escript.

Reading the numbers honestly

  • Throughput deltas under ~15 % are inside run-to-run variance on a loaded dev box. The bench's banner reminds on every run.
  • p50 / p99 are usually steadier than throughput run-to-run.
  • Loopback hides NIC + kernel TCP cost. For a public comparison run against a remote host with --clients tuned to your CPU count.