76 lines
3.7 KiB
Markdown
76 lines
3.7 KiB
Markdown
# Performance reference
|
|
|
|
The PLAN §18 targets and the numbers measured against them. Why the targets are
|
|
these targets, and why CI does not gate on them, is [performance and
|
|
testing](../explanation/performance-and-testing.md). To reproduce the numbers,
|
|
see [measure performance](../how-to/measure-performance.md).
|
|
|
|
## Targets (PLAN §18)
|
|
|
|
| Target | Where it is checked |
|
|
| --- | --- |
|
|
| Sustained ≥ 100 qps on Raspberry Pi 5 | End-to-end against the real binary on the Pi; not a harness number |
|
|
| Blocklist lookup p95 < 1 ms | `bench filter`: `matcher.normalize` + `Snapshot.evaluate` per op |
|
|
| Cached response p95 < 5 ms | `bench cache`: `buildKey` + `DnsCache.get` + `packet.setId` per op |
|
|
| Memory with ~1M blocked domains < 100 MiB | `bench filter`: VmRSS with the 1M-domain snapshot loaded |
|
|
| Stripped static binary ≤ 10,485,760 bytes per arch without the embedded frontend, ≤ 15,728,640 bytes with it | `zig build verify-dist`, run by the `package` gate and by the release |
|
|
|
|
The harness is `tools/bench.zig`. It measures the three targets that are
|
|
measurable in process; the qps target is end to end and the binary-size target
|
|
belongs to the packaging step.
|
|
|
|
The two size budgets are exact byte counts, not rounded mebibytes, because an
|
|
assert on a rounded number is an assert on a number nobody wrote down.
|
|
`verify-dist` checks the shipped binary against the larger budget and builds a
|
|
second time against a generated empty assets directory for the smaller one, so
|
|
the asset-free figure is a real measurement rather than an estimate.
|
|
|
|
## Measured: x86_64 development host
|
|
|
|
Date: 2026-08-02. Hardware and build: Intel Core i7-14700K, Linux 6.18,
|
|
Zig 0.16.0, `-Doptimize=ReleaseFast`, harness defaults (1,000,000 domains,
|
|
200,000 iterations per suite, seed 0x5eed).
|
|
|
|
This is not the target platform. The Pi 5's Cortex-A76 is far slower and these
|
|
numbers do not transfer; they establish that the harness works and set a
|
|
baseline for regressions on the machine development happens on.
|
|
|
|
```
|
|
suite ops p50(us) p95(us) p99(us) max(us)
|
|
filter 200000 0.11 0.18 0.27 16.41
|
|
blocked 66699/200000, Snapshot.memoryBytes 28.0 MiB, VmRSS 31.8 MiB
|
|
target p95 < 1ms: PASS
|
|
target VmRSS < 100 MiB: PASS
|
|
cache 200000 0.10 0.14 0.17 3.53
|
|
hits 100000/200000, DnsCache.memoryBytes 4.3 MiB, VmRSS 7.6 MiB
|
|
target p95 < 5ms: PASS
|
|
compile 1000000 wall 96.025ms, 10413949 lines/s, 1000000 domains kept (informational)
|
|
```
|
|
|
|
Every in-process §18 target passes on this host: the two latency targets by
|
|
three to four orders of magnitude, the memory target by about 3x.
|
|
|
|
### The two memory figures
|
|
|
|
`Snapshot.memoryBytes` and `DnsCache.memoryBytes` are the in-repo accounting of
|
|
the structures themselves, which is the regression guard. VmRSS is what the
|
|
kernel holds resident for the whole process, allocator slack and code included.
|
|
The truth sits between them, and the §18 memory target is judged on VmRSS.
|
|
|
|
The filter suite frees the generated list source before reading VmRSS, so its
|
|
number reflects the loaded snapshot rather than the generator. The cache suite's
|
|
VmRSS is lower because the filter suite's snapshot has been freed by then.
|
|
|
|
## Raspberry Pi 5 (target platform)
|
|
|
|
| Target | Result |
|
|
| --- | --- |
|
|
| Blocklist lookup p95 < 1 ms | to be measured on hardware |
|
|
| Cached response p95 < 5 ms | to be measured on hardware |
|
|
| Memory with ~1M blocked domains < 100 MiB | to be measured on hardware |
|
|
| Sustained ≥ 100 qps | to be measured on hardware, end to end |
|
|
|
|
The qps target belongs to the real binary rather than the harness: it means
|
|
`nxdns run` on the Pi, driven over the LAN by a DNS load generator against real
|
|
blocklists.
|