A Claim Needs a Table
"Our own service is better than SSH" is a claim, and a claim about speed is cheap until someone measures it. Delta shipped with a bench script, bench/compare.py, that runs the same pulls with Delta, rsync and scp against the same peer. It has two rules that make its numbers worth reading:
- Every result is checked. Each copy is compared with its source by SHA-256, and the line that reports its time says
verifiedorMISMATCHbeside it. The script does not throw a mismatched time away; it brands it, so a fast tool that landed the wrong bytes is caught in the very row it would have won. The architecture document's pull rows come from these checked runs; its two push rows were timed through the CLI, outside this check. - Same wire for everyone. In the house,
sshdials the same address Delta's route chose, with the peer's trusted host key. On the tailnet, both go over the tailnet. For "away", both run throughbench/away_proxy.py, a loopback proxy that gives every byte 40 Mbit/s each way and an 80 ms round trip, the way one hotel link would. The peer still sees the real caller, so neither tool's authentication changes.
The Results (2026-11-09)
One Mac pulling from another (bench/compare.py), plus two push rows run the other way through the CLI; for the first of them, all three tools dialed the same Thunderbolt address. "Small" is 4,000 files (74 MB). "Away" is a 128 MiB file, and separately 500 small files (9.5 MB).
| Case | Delta | rsync | scp |
|---|---|---|---|
| LAN, 1 GiB (Delta on Thunderbolt) | 0.34 s | 4.36 s | 1.73 s |
| LAN, 4,000 small files | 1.98 s | 1.15 s | 2.16 s |
| tailnet, 1 GiB | 19.65 s | 23.05 s | 22.84 s |
| tailnet, 4,000 small files | 2.27 s | 1.44 s | 23.47 s |
| away, 128 MiB | 28.98 s | 28.14 s | 28.56 s |
| away, 500 small files | 2.37 s | 3.23 s | 187.8 s |
| resume: 1 GiB stopped at 560 MiB, run again | 0.17 s for the rest | — | — |
| push, 1 GiB | 1.03 s (1.49 s first, with the link probe) | 2.67 s | 1.56 s |
| push again, the file already in place | 0.41 s | — | — |
Reading It Honestly
rsync still wins on many small files over a fast link. The doc says so, and so does this lesson. rsync sends everything in one stream and does not fsync each file. Delta fsyncs every file it lands, because a file Delta reports as landed must survive a power cut. That is a deliberate cost, paid where it is visible.
Away from home, the link decides. For the 128 MiB file, all three tools take about 28 to 29 seconds, because 40 Mbit/s is the limit and every tool reaches it. The small-file case shows the cost of round trips instead. scp pays at least one round trip per file and takes 187.8 s. Delta's bundles take 2.37 s, ahead of rsync's 3.23 s.
The big wins are the fast wires and the parallel chunks. 0.34 s for 1 GiB is about 25 Gbit/s, which needs both the Thunderbolt route (Track 3) and several workers on one file (lesson 2).
And the case that started all of this is not in the table. Loomis's Eagle grid, 384 thumbnails read from another Mac: through per-item SSH, 152 failed, 32.6 s wall, p50 3.8 s. Through Delta, none failed, 1.94 s cold (p50 0.19 s, p99 0.30 s), and 1.67 to 1.88 s warm, with every tile a 304 and no new bytes.
The Second Measurement: Before and After a Review
A day later, bench/measure.py measured Delta against itself: one peer, both directions, with the daemon's CPU and peak memory beside each case. "Before" is build 24, "after" is build 30 on both ends.
| Case (Thunderbolt) | before | after |
|---|---|---|
| push 4 GiB | 1.65 s | 1.23 s |
| pull 4 GiB, the source never hashed it | 3.59 s | 1.44 s |
| push 4,000 small files | 2.70 s | 1.11 s |
| list 4,040 entries | 0.267 s | 0.032 s |
| daemon peak memory in the run | 616 MB | 302 MB |
Listing was the steady cost, because two background users list trees all day: the vault pair once a minute, and a site-assets check every five minutes. A listing cost 104 µs per entry, 62% of it a privacy guard asked once per entry and 23% a loop over refused names. After the review it cost 12 µs per entry. A content tree of 17,861 entries went from 1,865 ms to 221 ms.
Anything Per Piece Is Constant-Cost
The sharpest lesson came from a regression the review itself introduced. Lesson 3 made progress report per 256 KiB piece. At 20 Gbit/s that is about ten thousand reports a second. The job's rate window kept one entry per report and summed the whole window on every report. Right after the first rollout, a 4 GiB push over Thunderbolt took 4.06 s where it had taken 1.65 s. The test suite passed both before and after, because tests run on small files and slow paths. Only a measurement on a fast link showed it. The window is now a handful of tenth-of-a-second buckets, and a report adds to the newest bucket. The rule went into the house sign: anything called per piece or per entry must cost the same no matter how many came before, and you measure after a change, on a fast link.