Benchmark results

View Source

Captured by scripts/bench_matrix.sh on 2026-05-15 at 90fba12.

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
hello287 k189 k281 k115 µs / 1.7 ms
json290 k194 k316 k115 µs / 1.7 ms
echo284 k153 k294 k123 µs / 1.5 ms
headers_heavy254 k143 k249 k135 µs / 1.8 ms
large_response121 k95 k129 k315 µs / 3.0 ms
multi_request_body271 k120 k275 k129 µs / 1.5 ms
varied_paths_router292 k168 k119 µs / 1.4 ms
post_4kb_form174 k95 k220 µs / 1.8 ms
large_post_streaming19 k7.0 k2.5 ms / 5.9 ms
pipelined_h1572 k362 k4.8 k69 µs / 609 µs
websocket_msg_throughput231 k171 k153 µs / 1.9 ms
gzip_response137 k108 k287 µs / 2.2 ms

HTTP/2

scenarioroadrunnercowboyellirr p50 / p99
hello172 k166 k215 µs / 2.5 ms
json167 k151 k224 µs / 2.4 ms
echo163 k118 k237 µs / 2.1 ms
headers_heavy163 k89 k240 µs / 2.1 ms
multi_request_body138 k33 k285 µs / 2.5 ms
multi_stream_h2350 k339 k126 µs / 379 µs
streaming_response61 k60 k644 µ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.