Performance overview
This page gives you the benchmark framing needed to evaluate NodalMerge performance without overfitting to single-run numbers. Use it as the entry point before diving into attribution or operation-specific benchmark artifacts.What benchmarks should answer
NodalMerge benchmarking should answer:- Is current behavior within acceptable performance budgets?
- Did a change cause meaningful regression?
- Which layer likely caused the change?
- Is the system still safe to promote under expected workload shape?
Benchmark dimensions that matter
At minimum, benchmark matrices should vary:- Peer cardinality
- Operation mix (map/list/blob)
- Payload sizes
- Auth/policy posture
- Runtime host surface
Scenario classes
Maintain at least these scenario classes:- Steady-state sync: typical collaborative command mix
- Auth/policy-enabled: capability and governance overhead posture
- Blob-sensitive: payload-heavy behavior
- Replay/validation: deterministic reconstruction cost
- Lifecycle-sensitive: persistence/GC/topology side effects under load
Baseline vs candidate methodology
For credible comparisons:- Keep scenario matrix fixed.
- Run baseline and candidate in alternating sequence when possible.
- Capture environment metadata (hardware/runtime/OS).
- Compare per-dimension deltas, not only aggregate averages.
Reading results safely
When interpreting results:- Look at map/list/blob separately
- Compare p95/p99 and not only mean
- Validate stability across peer-count tiers
- Cross-check with runtime attribution signals
Suggested decision bands
Use configurable decision bands for release gating:- Green: deltas within agreed operation-specific budgets
- Yellow: investigate and justify before promotion
- Red: block promotion pending fix or explicit risk acceptance
Benchmark artifact hygiene
Treat benchmark outputs as release artifacts:- Timestamped result files
- Baseline/candidate pair tracking
- Scenario metadata embedded in results
- Clear provenance of tooling/version
Common benchmark anti-patterns
- Comparing non-equivalent environments
- Using one benchmark flavor to represent all workloads
- Ignoring auth/policy-enabled scenarios
- Ignoring blob-heavy cases
- Treating microbench wins as guaranteed product-level wins
What to do after a regression
- Confirm reproducibility with rerun.
- Identify affected dimension (map/list/blob, peers, host, auth mode).
- Check runtime attribution to isolate likely layer.
- Decide: optimize, accept with rationale, or revert.
Latest results
Run date: 2026-07-01. First full re-run since theactivesync → nodalmerge rename
(the benchmark harness itself already used current naming; the matrix config’s env
var keys did not — see caveat below).
Environment: AMD Ryzen 9 5900X (12C/24T), 64 GB RAM, Windows 11 Pro. This is a
different host than the 2026-05-22 numbers previously recorded for this project (an
ASUS ProArt P16 laptop) — do not diff these results against that note’s absolute
numbers or deltas; only same-host runs are comparable. Treat this run as a fresh
same-host baseline.
Scenario: Run-BenchmarkMatrix.ps1 rows baseline-default-auth and
auth-enforced-room-lock-tokened (single A/B pair, not alternated). Targets:
rust-combined-server, dotnet-host-runtime-alias. Peers: 2/10/20. Command mix:
map60/list60/blob20@4k, 3 iterations per cell. (rust-integrated-hosted-server
was skipped — it’s optional and requires MONGO_URI.)
Aggregate deltas (auth-enforced vs baseline, positive = auth is slower):
Auth overhead was not observable in this run — deltas are flat to negative across
every dimension, well inside single-A/B-pair noise. This differs from the
2026-05-22 note’s alternated (A-B-A-B) result of roughly
+2% to +8% overhead,
but the two are not directly comparable (different host, single-pair vs
2x-averaged). Re-run with alternation on this host before concluding overhead has
actually changed.
Known caveat: blob operations in this harness log direct upload failed; falling back to ws on every call and fall back to the WebSocket blob path. Blob
timings above reflect that fallback path, not the direct-upload path — this has
been true since at least the 2026-05-22 run and is a harness/environment
limitation, not a regression.
Realtime WS host baseline (2026-07-22)
Same-host stats snapshot for the realtime WebSocket + persistence path after two host latency fixes landed on the native Rust hosts:TCP_NODELAY enabled on every
accepted connection (Kestrel does this by default; without it Nagle plus delayed-ACK
adds a small-frame round-trip stall). These are absolute stats, not a baseline/candidate
delta — see the methodology caveats below.
Environment: AMD Ryzen 9 5900X (12C/24T), 64 GB RAM, Windows 11 Pro. Same host
as the 2026-07-01 run above; do not diff against other-host notes.
Scenario: run_bench.ps1 (SDK scenario runner). Targets
rust-integrated-hosted-server (Mongo-backed dev-server, :7979) and
dotnet-host-runtime-alias (Mongo-backed, :8787). Peers: 6. Command mix:
map/list/blob at 6/12/30 ops, 1 KB blobs, ws-only transport, 15 iterations per
cell, 4 warmup ops, 2 ms op delay.
Results (avg / p95 ms, lower is better):
Map:
List:
Blob:
Warmup averaged ~46 ms on both hosts. Map and blob are near-parity at 12 ops; list
remains .NET-favored across the sweep, and .NET keeps an edge at 30 ops.
Caveats:
- Single run per cell, not alternated A/B. Per this page’s own methodology, treat this as a directional same-host snapshot, not release-grade gating evidence. Thermal/load drift of several ms between runs is expected — repeat runs of the identical build moved the unchanged .NET numbers by 5–8 ms, so sub-~20 ms differences here are within noise.
- Blob path is the WebSocket fallback. Blob timings reflect the
direct upload failed; falling back to wsfallback, not the direct-upload path — the same harness limitation noted in the run above. - Target differs from the 2026-07-01 entry.
rust-integrated-hosted-serveris the Mongo-backed dev-server; the earlier “Latest results” block usedrust-combined-server(no Mongo). The two result blocks are not directly comparable. - Provenance: build from branch
host-latency-nodelay-connect-tax(TCP_NODELAYon all native hosts + per-connection connect-tax removed).