Benchmarks

2026-10-06 — Per-core loops, open file cache, kTLS, slimmer request path

Same harness, host and caveats as the other reports (Docker Desktop / WSL2, Ryzen 7 7800X3D, server on CPUs 0-3, applications 4-5, oha on 6-11, 64 connections, 10 s; ±15–20 % run-to-run). Both servers configured alike: open file cache with a check per hit (OPEN_FILE_CACHE=check), kernel TLS on (KTLS=1, tls module loaded).

Final comparison (one run; two nginx rows replaced by repeats, see below)

scenario               scb      nginx    caddy    scb/nginx   before (scb/nginx)
static-small         99.8k    121.9k    32.4k      0.82×       0.61–0.71×
static-1m            21.4k     23.7k    13.9k      0.90×       0.42×
respond             151.9k    242.4k    54.9k      0.63×       0.48×
proxy                68.1k     85.9k    25.6k      0.79×       0.66×
cache-hit           127.4k     93.6k    25.2k      1.36×       1.2×
tls-h2-static-small  86.7k     73.7k    23.3k      1.18×       0.64×
tls-static-1m (h1)   5.0–6.0k   6.1k     2.4k      0.82–0.98×  (new; 1.34× without kTLS)
php                 15.2–18.6k 20.6–21.7k 7.8k     0.75–0.87×  0.93–1.0×
node                 20.3k     22.6k    25.2k      0.90×       ≈1×
python               11.3k     10.7k    13.3k      1.05×       ≈1×

Peak RSS: scb 38–53 MiB (mimalloc, four runtimes), nginx 59–76 MiB, Caddy 47–61 MiB.

In the single run nginx showed 3.6k on tls-static-1m (23 CPU-s of 40) and 7.2k on php (7.9 CPU-s); two repeats of those scenarios gave 6.1k/6.1k and 21.7k/20.6k, which are used above. respond varies most between runs (nginx 177–268k, scb 117–167k).

What changed and what each step measured

StepMeasurement
Open file cache (ADR-0028)small files 72.2k → 79.4k; trusting entries for 60 s gained nothing more for scb (nginx +46 %)
Per-core event loops (ADR-0029)respond 97.9k → 116k; minimal config 72k → 157k (= four separate processes)
Cache stage: hit-for-pass, sharded coalescing map, pre-resolved countersrespond with cache enabled 117k → 142k
Direct hyper builders instead of hyper-util autobare-hyper probe: auto layer −14 %; in scb 22.2 → 21.6 µs/request
Per-loop FastCGI and upstream poolsphp 12.3–13.3k → 15.9–18.0k
mimallocproxy +17 %, cache-hit +26 % (two-run averages), +20 MiB RSS
kTLS (ADR-0030)HTTPS/1.1 1 MiB 3.9k → 6.2k (nginx 6.1k with kTLS)

Where the remaining gap is

  • Per-request CPU on respond: scb ≈ 21–23 µs, nginx ≈ 14–15 µs; split by DSO the kernel part is 15.6 vs 10.7 µs and user space 9.2 vs 3.4 µs.
  • A bare hyper server on the same per-core loops reaches 238–254k (≈ nginx); a raw httparse server 289k. The remaining ~6 µs are scb’s own layers (routing, context, metrics, body wrappers), spread over many small items — no single hotspot.
  • Applications behind scb (PHP, Node) lost a little with per-core loops; per-loop pools recovered most of PHP. Single-loop measurements show the WSL loopback leaving one loop ~30 % idle, so part of this may be environmental; a bare-metal run is still open.