Measured, not claimed

Performance

Numbers from the project's own benchmark harness (make bench-full), on loopback, with the raw results one click away.

AMD Ryzen 5 5500U with Radeon Graphics (12 threads, x86_64, Linux 6.8.0) · 4 DNS workers · 2026-10-04 · commit c67ccba · raw results (JSON)

CorpusPeak qpsLoadOffered qpsp50p99Loss
cache-hot172,58025%43,14434 µs303 µs0.00%
50%86,28937 µs1.6 ms0.00%
75%129,43447 µs2.9 ms0.00%
blocked154,38125%38,59535 µs575 µs0.00%
50%77,19036 µs975 µs0.00%
75%115,78537 µs1.7 ms0.00%
miss-heavy—fixed rate2,000103 µs251 µs0.00%

Server: ready in 76 ms, filter ready in 5.5 s, 89 MiB idle and 354 MiB peak RSS with 5 blocklists loaded. 3 runs of 30 s per corpus; each number is the median across runs. Load generator: dnsperf 2.14.0, 2 threads, 8 clients.

By transport

Intel(R) Core(TM) i5-1035G4 CPU @ 1.10GHz (8 threads, x86_64) · 2026-10-06 · raw results (JSON)

TransportPeak qpsp50 at 50%p99 at 50%Loss
UDP199,47675 µs879 µs0.00%
TCP229,386359 µs2.7 ms0.00%
DoT91,903235 µs3.0 ms0.00%
DoH (HTTP/2)147,803771 µs2.6 ms0.00%

The same cache-hit corpus over each transport, from one node with a throwaway certificate. UDP, TCP, and DoT from dnsperf; DoH from h2load (RFC 8484 GET). The load generator runs on the same machine, so compare the rows with each other rather than with other hosts.

How to read this: peak is the most queries per second the server answered with no loss while dnsperf pushed as hard as it could on the same machine; latency at peak is mostly queueing in the load generator. The at 25 / 50 / 75% load rows replay a fixed rate below that peak: that's what devices on a home network experience. cache-hot asks 10,000 names repeatedly (answers from the cache), blocked asks names on the blocklists (answered by the filter, about 2.7 million names loaded), and miss-heavy sends unique names at a fixed 2,000 per second, each one resolved through a local stub upstream. Harness details: bench/README.md.

Against the v1.0 targets

The release gate for 1.0 sets targets for speed and footprint. These were measured on the shipped build, with the method for each one in docs/v1-gate.md.

WhatTargetMeasured
Time to answer from the cache or the blocklists, at half the maximum load sent from another machinep99 ≤ 250 µs99.999 % of answers sent within 250 µs (p99 within 50 µs), with no queries lost
Memory at idle, no lists≤ 20 MiB13.7 MiB
Memory with a million blocked names, 100,000 cached answers, and telemetry≤ 64 MiB60 MiB
Raspberry Pi 4: new rules answering after a 2-million-name list changes≤ 8 s4.7 s (the rest of the compile finishes in the background)
Start to serving, with the filter on disk≤ 500 ms52 ms with a million names
Compressed container image≤ 15 MiB10.6 to 11.1 MiB per architecture

Still open before 1.0: throughput on a Raspberry Pi 4 that isn't serving a home network, and how fast a change reaches every node, measured over more changes.

Screenshots of the UI moved to the Tour; what TelltaleDNS measures and alerts on is on Monitoring.