Performance and Benchmarks
This page collects the performance notes moved out of the README and keeps public benchmark snapshots by version. The goal is not to claim an absolute winner, but to show the performance profile of ForgeDNS under different levels of policy complexity, concurrency, and transport-path pressure.
What ForgeDNS Cares About
ForgeDNS is not only interested in peak numbers for the simplest possible case. The more relevant questions are:
- Is the hot path still controlled when cache, rules, fallback, and rewrites are enabled?
- Is overall latency acceptable when several upstreams race concurrently?
- Can the structure still be optimized after adding more protocols and plugins?
- Do system integrations and observability stay off the critical response path enough to avoid dragging performance down?
Metric Notes
- Higher
QPSis better - Lower average latency and latency stddev are better
run_dnsperf_compare.shis better for saturated or higher-concurrency throughput and queueing behaviorrun_dnsperf_latency_compare.shis better for low-concurrency latency, withclients == outstanding- These snapshots are better read as version-specific distributions of strengths against mosdns
- Because the 2026-04-13 compare pack updated the scenario catalog, query sets, and some workload definitions, the absolute numbers in
v0.1.0andv0.3.0should not be treated as a direct regression chart across versions
Legend:
- Green means ForgeDNS performs better on that metric
- Red means mosdns performs better on that metric
- Neutral means the gap is small and shown only as a reading aid, not as a claim of statistical significance
v0.3.0
Higher-Concurrency Throughput and Average Latency
Test environment:
- Date: 2026-04-13
- System: Linux
6.8.12-2-pvex86_64 - Selector:
core - Compared versions: ForgeDNS
v0.3.0, mosdnsv5.3.4-0-gb732318
Load-test parameters:
- Tool:
dnsperf warmup_seconds=2bench_seconds=8bench_repeats=3dnsperf_clients=32dnsperf_threads=4dnsperf_outstanding=1024dnsperf_max_qps=unlimited
How to read these results:
- Scenarios such as
baseline UDP forward,concurrent upstreams, anddual-entry UDP/TCPinclude upstream forwarding or upstream races, so they mainly reflect end-to-end proxy behavior; upstream RTT, upstream response stability, and race strategy matter more here than small local processing differences cache hotpath,local answers, andserver local UDP/TCPare closer to local processing costdomain setandcomposite provider chainare better indicators for rule-heavy and dataset-heavy policy workloads
The table below shows the per-scenario medians aggregated from repeats:
| Scenario | ForgeDNS QPS | mosdns QPS | QPS Delta | ForgeDNS Avg Latency | mosdns Avg Latency |
|---|---|---|---|---|---|
| baseline UDP forward | 35,498.1 | 36,883.2 | -3.8% | 7.735 ms | 11.244 ms |
| cache hotpath | 139,133.9 | 134,881.6 | +3.1% | 0.637 ms | 0.721 ms |
| dual-entry UDP | 35,800.9 | 35,382.3 | +1.2% | 7.092 ms | 10.170 ms |
| dual-entry TCP | 37,295.1 | 37,221.2 | +0.2% | 24.646 ms | 25.083 ms |
| concurrent upstreams | 21,038.7 | 13,319.4 | +58.0% | 10.404 ms | 20.601 ms |
| local answers | 126,268.4 | 149,119.6 | -15.3% | 0.783 ms | 0.639 ms |
| domain set | 165,647.7 | 36,383.7 | +355.3% | 0.549 ms | 4.078 ms |
| ip set | 133,355.1 | 150,756.7 | -11.5% | 0.740 ms | 0.637 ms |
| composite provider chain | 158,693.6 | 25,972.4 | +511.0% | 0.532 ms | 6.251 ms |
Low-Concurrency Latency Sweep
Test environment:
- Date: 2026-04-13
- System: Linux
6.8.12-2-pvex86_64 - Selector:
latency-core - Compared versions: ForgeDNS
v0.3.0, mosdnsv5.3.4-0-gb732318
Load-test parameters:
- Tool:
dnsperf warmup_seconds=1bench_seconds=5bench_repeats=3latency_client_levels=1 2 4dnsperf_threads=1dnsperf_timeout=5dnsperf_outstanding=matches_client_count
The three tables below focus on average latency and jitter first, while QPS remains a secondary sanity metric. They use the same color rule as above: lower latency or jitter is green, higher latency or jitter is red, and ties are neutral.
clients=1, outstanding=1
| Scenario | ForgeDNS Avg Latency | mosdns Avg Latency | Latency Delta | ForgeDNS Jitter | mosdns Jitter | Jitter Delta |
|---|---|---|---|---|---|---|
| baseline UDP forward | 6.716 ms | 5.708 ms | +17.66% | 0.170 ms | 1.140 ms | -85.09% |
| cache hotpath | 0.029 ms | 0.031 ms | -6.45% | 0.017 ms | 0.021 ms | -19.05% |
| dual-entry UDP | 5.949 ms | 6.394 ms | -6.96% | 0.426 ms | 2.364 ms | -81.98% |
| dual-entry TCP | 5.984 ms | 6.118 ms | -2.19% | 0.380 ms | 0.829 ms | -54.16% |
| local answers | 0.026 ms | 0.029 ms | -10.34% | 0.016 ms | 0.019 ms | -15.79% |
| domain set | 0.025 ms | 0.108 ms | -76.85% | 0.011 ms | 0.095 ms | -88.42% |
| composite provider chain | 0.025 ms | 0.156 ms | -83.97% | 0.012 ms | 0.129 ms | -90.70% |
| server local UDP | 0.025 ms | 0.027 ms | -7.41% | 0.013 ms | 0.013 ms | +0.00% |
| server local TCP | 0.027 ms | 0.030 ms | -10.00% | 0.009 ms | 0.018 ms | -50.00% |
clients=2, outstanding=2
| Scenario | ForgeDNS Avg Latency | mosdns Avg Latency | Latency Delta | ForgeDNS Jitter | mosdns Jitter | Jitter Delta |
|---|---|---|---|---|---|---|
| baseline UDP forward | 6.001 ms | 7.382 ms | -18.71% | 0.262 ms | 0.858 ms | -69.46% |
| cache hotpath | 0.033 ms | 0.037 ms | -10.81% | 0.050 ms | 0.053 ms | -5.66% |
| dual-entry UDP | 6.408 ms | 5.923 ms | +8.19% | 1.247 ms | 0.488 ms | +155.53% |
| dual-entry TCP | 5.651 ms | 5.633 ms | +0.32% | 0.417 ms | 0.518 ms | -19.50% |
| local answers | 0.040 ms | 0.031 ms | +29.03% | 0.021 ms | 0.018 ms | +16.67% |
| domain set | 0.029 ms | 0.111 ms | -73.87% | 0.013 ms | 0.104 ms | -87.50% |
| composite provider chain | 0.029 ms | 0.165 ms | -82.42% | 0.014 ms | 0.141 ms | -90.07% |
| server local UDP | 0.030 ms | 0.029 ms | +3.45% | 0.016 ms | 0.016 ms | +0.00% |
| server local TCP | 0.028 ms | 0.030 ms | -6.67% | 0.014 ms | 0.015 ms | -6.67% |
clients=4, outstanding=4
| Scenario | ForgeDNS Avg Latency | mosdns Avg Latency | Latency Delta | ForgeDNS Jitter | mosdns Jitter | Jitter Delta |
|---|---|---|---|---|---|---|
| baseline UDP forward | 5.977 ms | 5.910 ms | +1.13% | 0.355 ms | 2.700 ms | -86.85% |
| cache hotpath | 0.044 ms | 0.060 ms | -26.67% | 0.028 ms | 0.063 ms | -55.56% |
| dual-entry UDP | 6.637 ms | 5.426 ms | +22.32% | 25.556 ms | 0.435 ms | +5774.94% |
| dual-entry TCP | 6.451 ms | 6.941 ms | -7.06% | 4.422 ms | 26.437 ms | -83.27% |
| local answers | 0.056 ms | 0.040 ms | +40.00% | 0.030 ms | 0.025 ms | +20.00% |
| domain set | 0.034 ms | 0.155 ms | -78.06% | 0.016 ms | 0.141 ms | -88.65% |
| composite provider chain | 0.034 ms | 0.221 ms | -84.62% | 0.015 ms | 0.172 ms | -91.28% |
| server local UDP | 0.042 ms | 0.038 ms | +10.53% | 0.024 ms | 0.024 ms | +0.00% |
| server local TCP | 0.042 ms | 0.039 ms | +7.69% | 0.026 ms | 0.022 ms | +18.18% |
v0.3.0 Result Readout
- If your real deployment relies on complex rule sets, large datasets, or multi-upstream racing, ForgeDNS is in a stronger position in
v0.3.0;domain set,composite provider chain, andconcurrent upstreamsare all clearly ahead. cache hotpathnow shows a small lead for ForgeDNS, which means the gap on high-frequency cache-hit traffic has narrowed substantially.- In local-answer workloads, the gap between ForgeDNS and mosdns is already fairly small; the
ip setresult is also more constrained by the local-answer performance ceiling than by a completely separate bottleneck. - For
forward,dual-entry, andconcurrent upstreams, the numbers should be read as end-to-end proxy behavior. Upstream latency and upstream response stability are the dominant factors there, not just local implementation overhead. - In the low-concurrency latency sweep,
domain set,composite provider chain,cache hotpath, andserver local TCPare the most stable strong areas;dual-entry UDPshows noticeably higher jitter atclients=4, so that scenario still needs more stability work.
v0.1.0
The following public result set is preserved as the historical v0.1.0 snapshot from March 26, 2026.
Higher-Concurrency Throughput and Average Latency
Test environment:
- CPU: Intel N100, 4 cores
- Memory: 1 GB
- Environment: LXC inside a PVE VM
- System: Linux
6.8.12-2-pvex86_64 - Date: 2026-03-26
- Compared versions:
forgedns v0.1.0, mosdnsv5.3.4-0-gb732318
Load-test parameters:
- Tool:
dnsperf warmup_seconds=2bench_seconds=8bench_repeats=3dnsperf_clients=32dnsperf_threads=4dnsperf_outstanding=1024dnsperf_max_qps=unlimited
The table below shows the average of three runs for each scenario:
| Scenario | ForgeDNS QPS | mosdns QPS | QPS Delta | ForgeDNS Avg Latency | mosdns Avg Latency |
|---|---|---|---|---|---|
| baseline UDP forward | 37,789.6 | 37,269.2 | +1.4% | 9.142 ms | 12.312 ms |
| cache hotpath | 131,982.3 | 133,380.3 | -1.0% | 1.235 ms | 0.696 ms |
| dual-entry UDP | 39,614.4 | 34,356.8 | +15.3% | 8.946 ms | 10.009 ms |
| dual-entry TCP | 36,257.9 | 35,975.4 | +0.8% | 25.403 ms | 25.577 ms |
| concurrent upstreams | 21,694.8 | 13,195.4 | +64.4% | 15.065 ms | 23.790 ms |
| fallback standby | 22,259.9 | 23,223.9 | -4.2% | 16.376 ms | 10.616 ms |
| local answers | 132,286.6 | 146,754.3 | -9.9% | 1.250 ms | 0.636 ms |
| DoH upstream (HTTP/2) | 29,781.6 | 25,835.7 | +15.3% | 13.363 ms | 11.445 ms |
| domain set | 172,061.7 | 35,966.1 | +378.4% | 0.901 ms | 4.210 ms |
| ip set | 134,257.4 | 150,923.0 | -11.0% | 1.227 ms | 0.625 ms |
| sequence base | 131,995.6 | 150,301.5 | -12.2% | 1.265 ms | 0.622 ms |
| match true | 135,326.0 | 153,289.5 | -11.7% | 1.217 ms | 0.629 ms |
| match false | 136,740.1 | 152,297.5 | -10.2% | 1.201 ms | 0.630 ms |
| match qname | 132,289.4 | 152,203.6 | -13.1% | 1.248 ms | 0.638 ms |
v0.1.0 Historical Readout
- ForgeDNS was stronger in concurrent upstream races, DoH upstreams, dual-entry UDP, and large
domain_setscenarios - mosdns was still faster in cache-hit paths, local answers, basic
sequence, and lighter matcher scenarios fallback standbystill showed room for further optimization
Raw Materials
- Benchmark directory:
benchmarks/mosdns_compare/README.md - Scenario list:
benchmarks/mosdns_compare/scenarios.tsv - Higher-concurrency script:
benchmarks/mosdns_compare/run_dnsperf_compare.sh - Low-concurrency latency script:
benchmarks/mosdns_compare/run_dnsperf_latency_compare.sh