tomo docs
home github

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.

tomo  save→arrival 6 ms rsync  one sync, any size ~370 ms 0 100ms 200ms 300ms 400ms milliseconds

linear scale — the thin coral line is tomo

Setup #

One machine, localhost. This is the friendliest possible case for rsync: no network round-trips, warm page cache, a beefy dev box. On a real laptop↔server link, rsync pays its scan cost plus latency on every invocation, while Tomo's save-to-arrival stays event-driven. Treat these as a lower bound on the gap, not an upper one.

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 changedRun 1Run 2Run 3
nothing (pure tree scan)350 ms363 ms410 ms
one file changed351 ms371 ms409 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:

Tool100 files → all landed
tomo520 ms
rsync (one invocation)367 ms
Mutagen 0.18.19,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:

ToolInitial full seed
rsync752 ms
tomo2.8 s
Mutagen 0.18.15.2 s
Seeding used to be Tomo's weak spot — it isn't anymore. Through v0.2.2 this number was 92.5 s (the per-file pipeline paid full crash-safety costs one file at a time). v0.2.3 batches the receiver — staged writes installed behind a single fsync barrier, with the per-file atomic rename (and so 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.
Pre-seeded trees work too. If the box already has the tree (an 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.

MetrictomoMutagen 0.18 (defaults)
save→arrival, median of 106 ms121 ms
save→arrival, best / worst5 / 32 ms94 / 539 ms
burst of 100 files, all landed520 ms9,393 ms
initial seed, 20k files2.8 s5.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 #