# Upstream pools and route matching: prefix-only regression check, 2026-10-14

URL: https://scalws.com/docs/benchmarks/2026-10-14-xeon-routing-pools-regression/
Source: `docs/benchmarks/2026-10-14-xeon-routing-pools-regression.md` in the ScalWS repository

Machine and pinning as in `2026-10-10-xeon-bare-metal-pgo.md`: 2× Xeon E5-2650 v2 (Ivy
Bridge EP, no AVX2), Ubuntu 26.04, kernel 7.0, `performance` governor, turbo off. Server
on CPUs 0-3 (four physical cores of socket 0, 4 workers), upstream and applications on
4-7, `oha` 1.16.0 on all of socket 1 (8-15, 24-31), 64 connections.

Commits: `base` = d61a50f (before Kubernetes phase 2a), `new` = 2384720 (upstream pools,
route matching and route policies). Both are plain release builds of the same profile
(`cargo build --release --locked -p scalwsd --features http3`, thin LTO, one codegen unit,
no PGO or BOLT, no target-specific CPU features); the shipped `bench/configs/scalws.yaml`
enables an HTTP/3 listener, so both need the `http3` feature. The numbers are therefore
lower than those of the PGO + BOLT builds in run 7 and are only comparable with each
other.

Configuration under test: `bench/configs/scalws.yaml` unchanged, which has prefix routes
only (`/api` to a single-address proxy, `/respond`), so `new` takes the prefix fast path
and the existing `ProxyHandler`. `bench/multi.sh` with `VARIANTS="base=... new=..."`,
`MODE=release`: 10 s warm-up, 30 s measurement, 5 runs, the order of the two variants
rotating from run to run; medians. Every measurement answered 2xx only; no run was
excluded.

Gate: `new` requests per second at least 0.98× `base` and server CPU per request at most
1.02× `base`, per scenario.

| scenario | base req/s | new req/s | new / base | cpu_us base | cpu_us new | cpu new / base | gate |
|---|---:|---:|---:|---:|---:|---:|---|
| static-small | 75 641 | 74 787 | 0.989 | 52.87 | 53.47 | 1.011 | pass |
| respond | 125 460 | 127 674 | 1.018 | 31.87 | 31.32 | 0.983 | pass |
| proxy | 51 601 | 51 055 | 0.989 | 77.50 | 78.33 | 1.011 | pass |
| cache-hit | 93 195 | 94 490 | 1.014 | 42.90 | 42.32 | 0.986 | pass |

Spread of the five runs (req/s, min to max, CV): static-small base 75 170-77 079 (0.9 %),
new 73 403-76 166 (1.6 %); respond base 124 536-128 275 (1.2 %), new 122 535-128 870
(2.5 %); proxy base 51 422-51 842 (0.3 %), new 50 227-51 442 (1.1 %); cache-hit base
92 142-94 571 (1.0 %), new 91 842-96 017 (2.0 %). The differences of static-small and
proxy (about 1 %) are inside the spread of the runs, and respond and cache-hit moved the
other way by a similar amount.

p99 latency (ms), base / new: static-small 1.07 / 1.07; respond 0.67 / 0.65; proxy
2.04 / 2.23; cache-hit 0.92 / 0.89.

Peak resident memory of the server (MiB), base / new: static-small 44 / 43; respond
43 / 43; proxy 45 / 51; cache-hit 45 / 51. The value is the peak since the server
started (the four scenarios run against one process in this order), so proxy and
cache-hit include what the earlier scenarios left allocated. `new` peaked higher from the
proxy scenario on in every run (proxy: 46-51 MiB against 44-45 MiB); the cause is not
investigated here and it does not show up in CPU per request. The proxy p99 (+9 %) moved with the
throughput spread of the runs; the median latency is unchanged.

## Verdict

The gate holds on all four scenarios: no throughput drop above 2 % and no CPU per request
increase above 2 %. The prefix-only configuration costs the same with upstream pools,
route matching and route policies in the binary as before.

Results, in the bench host's results directory: `results/xeon-pools-ab` (`aggregate.csv`, `aggregate.txt`,
`run-1` ... `run-5`); binaries `/opt/scalws-pools-base/scalwsd` and
`/opt/scalws-pools-new/scalwsd`.
