Benchmarks
Numbers from one run on one machine. They're here to show the shape of the tradeoff, not to win an argument — measure your own setup before you trust any of them.
The number that matters #
Day to day, the only latency you feel is this: you hit save, and when does the file show up on the other box? On a 20,000-file tree, Tomo does that in a median of 6 ms. rsync isn't built for that question — you run it, and it rescans the whole tree first, which costs ~370 ms here before it even looks at what changed. That gap only widens: rsync's scan grows with the tree, with cold caches, and with real network latency; Tomo's doesn't, because it never scans.
linear scale — the thin coral line is tomo
Setup #
- Tree: a synthetic source tree of 20,000 files, ~200 MB total.
- Link: real SSH to
localhoston one machine (so there's zero network latency — a real network only makes rsync's per-run scan hurt more, not less). - Caches: warm. Every number below is a steady-state repeat, not a cold first touch.
- Binaries: Tomo 0.2.3 release build; rsync 3.2.7 (
-a, over SSH); Mutagen 0.18.1 (defaults). Measured 2026-07-23 on a fresh 20,000-file / ~200 MB tree.
Raw numbers #
Tomo save→arrival latency
Change one file, measure until it lands on the peer. Ten rounds on the warm 20,000-file tree:
5, 5, 5, 6, 6, 6, 6, 10, 16, 32 (ms) median 6 ms ยท worst 32 ms
The tail (16 ms, 32 ms) is normal jitter — a GC pause, a scheduler hiccup. The point is the median sits at single-digit milliseconds and doesn't care how big the tree is, because a save is an inotify/FSEvents event, not a scan.
rsync, per invocation
rsync has no persistent process; every sync is a fresh full-tree scan. Three runs each:
| What changed | Run 1 | Run 2 | Run 3 |
|---|---|---|---|
| nothing (pure tree scan) | 350 ms | 363 ms | 410 ms |
| one file changed | 351 ms | 371 ms | 409 ms |
Note that changing a file barely moves the number: rsync's cost is almost entirely the scan, not the transfer. So on this tree you pay ~350–400 ms every time you want changes to move, changed or not.
A burst of 100 changed files
The realistic middle ground — a build finishes, a coding agent lands a change, 100 files move at once. Time until all 100 are on the peer:
| Tool | 100 files → all landed |
|---|---|
| tomo | 520 ms |
| rsync (one invocation) | 367 ms |
| Mutagen 0.18.1 | 9,393 ms |
rsync edges Tomo here on localhost — one scan amortized over 100 files is its sweet spot (on a real link its scan pays latency Tomo doesn't). Mutagen batches bursts into multi-second reconciliation cycles.
Initial seed
This one goes the other way. Seeding the whole tree from scratch:
| Tool | Initial full seed |
|---|---|
| rsync | 752 ms |
| tomo | 2.8 s |
| Mutagen 0.18.1 | 5.2 s |
kill -9 safety) unchanged — and the seed dropped 33×. rsync is still faster at pure mirroring; the gap is now a few multiples, not orders of magnitude. One honest detail: after a big seed the file bytes land first and history capture finishes in the background over the next few seconds — the files are usable immediately, the version records follow.rsync -a, a git clone), tomo sync converges over it and takes over from there — you never pay the seed at all.Mutagen, same methodology #
Mutagen is the closest tool in spirit (real-time, two-way, over SSH), so it gets the same test: Mutagen 0.18.1, default settings, same 20,000-file tree, same localhost SSH link, same append-a-marker-and-poll measurement.
| Metric | tomo | Mutagen 0.18 (defaults) |
|---|---|---|
| save→arrival, median of 10 | 6 ms | 121 ms |
| save→arrival, best / worst | 5 / 32 ms | 94 / 539 ms |
| burst of 100 files, all landed | 520 ms | 9,393 ms |
| initial seed, 20k files | 2.8 s | 5.2 s |
Raw Mutagen latencies (ms): 94, 103, 105, 115, 119, 123, 124, 124, 176, 539. The latency gap is ~20×; where it widens is bursts — 100 changed files take Mutagen ~9.4 s of reconciliation to Tomo's 0.67 s — and as of v0.2.3 the seed column goes Tomo's way too (2.8 s vs 5.2 s). None of this makes Mutagen less excellent at what it's built for — fleet-grade managed sync. One measurement gotcha worth knowing: if you benchmark Mutagen yourself and see ~9–10 s latencies, check your inotify limits — when it can't get a native watcher it silently falls back to polling, and you're measuring its poll cadence, not the tool.
Why the shapes differ #
rsync is a batch tool: each run walks the entire tree, diffs it against the far side, and transfers what changed. That's a great model for periodic mirroring, and it's why its cost is dominated by tree size, not change size. Tomo is a long-running process on both ends: the OS tells it the moment a file changes, so it moves exactly that change and nothing else. There's no scan to pay for, which is why its latency is flat as the tree grows.
The other difference doesn't show up in a single number: Tomo is continuously bidirectional. Files flow both ways, live, the whole time the session is up. Getting that from rsync means gluing it to a file watcher (inotify + lsyncd, or a cron loop), running it in both directions, and hoping the two passes don't fight over a file mid-write. Tomo is that, as one process, with conflict handling built in.
Caveats #
- One machine, localhost SSH, warm cache, release builds. Your numbers will be different.
- rsync's numbers are close to its best case here (no network latency). A real link widens the gap in Tomo's favor for incremental sync.
- rsync still wins pure one-shot mirroring; Tomo's seed is within a few multiples of it as of v0.2.3.
- These measure wall-clock latency, not throughput. For big-file throughput and dedup behavior, see history & transfer.