Benchmarks

Bare metal (2× Xeon E5-2650 v2) and profile-guided builds — 2026-10-10

First measurements away from the noisy VM: 2× Xeon E5-2650 v2 (Ivy Bridge EP, 8C/16T per socket, no AVX2), 121 GB, Ubuntu 26.04, kernel 7.0, performance governor, turbo off. Server on CPUs 0-3 (four physical cores of socket 0, HT siblings idle), upstream and application processes on 4-7, oha on all of socket 1 (8-15, 24-31). MODE=quick, 3 runs; spread is about 1 % (the VM’s was 5–10 %). scalws cur = commit 4415c31 with both experimental settings, hyper = same binary with defaults.

Without PGO

scenariocurhypernginx 1.28nginx 1.31cur / 1.31
static-small81 68274 96394 02196 2130.85
static-1m8 7908 7658 8218 8311.00
respond140 186121 065199 690210 5440.67
proxy63 71750 17876 13089 7060.71
cache-hit105 70493 58180 64982 8261.28
tls-h2-static-small60 41860 90164 21768 3880.88
php28 37327 88916 48116 4631.72

Both servers saturate their four cores, so throughput is CPU per request. perf stat per request (respond): scalws 32.3k user cycles for 17.1k instructions (IPC 0.53) and 43.3k kernel cycles; nginx 14.3k user cycles for 9.9k instructions (IPC 0.69) and 34.9k kernel cycles. The kernel executes the same number of instructions for both (15.4k) but needs 24 % more cycles for scalws. Misses per request: L1i 2 610 vs 1 955, L1d 1 112 vs 674, branch 124 vs 88. The gap is mostly code and data footprint (instruction cache), which also slows the kernel’s share, rather than instruction count.

Profile-guided build

-Cprofile-generate, one quick run of the seven scenarios with both variants as training, llvm-profdata merge, -Cprofile-use. The training load is the benchmark load itself (the same request paths a real deployment serves, but a separate training set is still to be defined).

scenariopgo (experimental)pgo-hypernginx 1.31pgo / 1.31
static-small105 962101 56395 2721.11
static-1m8 8278 8538 8711.00
respond192 817170 723211 1140.91
proxy85 53172 92686 5640.99
cache-hit157 259148 31984 8771.85
tls-h2-static-small91 135 (CV 10 %)88 57766 9541.36
php31 27333 75317 0531.83

perf stat with PGO (respond): 18.0k user cycles (IPC 0.78), 37.4k kernel cycles — user cycles -44 %, kernel cycles -14 %. static-1m is bandwidth-bound for both.

Results: xeon:[private host path], xeon:[private host path].

tools/pgo-build.sh with BOLT (own training load, ADR-0047)

Built with PGO_BOLT=1 from commit 9eaebe7; the training load is the script’s own, not the benchmark. All scenarios ran without errors on the BOLT binary.

scenariofinal (experimental)final-hypernginx 1.28nginx 1.31final / 1.31
static-small105 757102 95793 58494 4161.12
static-1m9 8289 7869 8509 8381.00
respond199 953181 433192 272208 5900.96
proxy93 94676 53576 00786 0431.09
cache-hit156 901149 41380 28782 9961.89
tls-h2-static-small93 07691 48565 02566 9681.39
php31 26231 37116 40016 5181.89

Results: xeon:[private host path].