Benchmarks
fio
sandbox.exec, on a FUSE baseline (libfuse's passthrough_ll), and on the kernel's own overlayfs.
LayerFS against FUSE baseline
vs FUSE baseline- LayerFS
- core at main e5c7aaae05, through the JS SDK
- Tool
- fio 3.33 · psync, iodepth 1, 20 s per job
- Baseline
- libfuse passthrough_ll 3.14.0, a sibling container on the same VM
- Reference
- kernel overlayfs, the same Sandbox's own /tmp (no FUSE)
- Host
- arm64 Mac · Docker Desktop, linux/arm64, 8 CPUs, 8.3 GB
- Load
- 6.5–19.9 (1 min), three-arm run
Completeness and the Commit
9 / 9 PASS
every LayerFS job, O_DIRECT included · the FUSE baseline failed rand-write-direct
24.8 s
1.68 GB logical · 1.15 GB newly stored
Against a FUSE baseline
The like-for-like comparison: libfuse’s passthrough_ll (fuse-3.14.0) over a plain directory, writeback off, same jobs, same run. Where the filesystems themselves are compared, LayerFS is ahead in2 (randrw-70-30, rand-read-direct) and behind in 3 (seq-write, seq-read, rand-write). Rows the page cache answered on every arm, and the fsync row, are shown but not counted.
- seq-write0.31×514 MB/s / 1,669 MB/s
- seq-read0.81×5,031 MB/s / 6,228 MB/s
- rand-write0.40×33.1 MB/s / 82.0 MB/s
- rand-read1.41×page cache on every arm
- rand-read-4j1.16×page cache on every arm
- randrw-70-30 (read)2.23×102 MB/s / 45.5 MB/s
- randrw-70-30 (write)2.23×43.6 MB/s / 19.5 MB/s
- sync-write6.91×fsync: baseline flushes, Disposable does not
- rand-write-direct—baseline failed (EINVAL)
- rand-read-direct1.49×54.4 MB/s / 36.6 MB/s
The reference is not like-for-like
Kernel overlayfs is the Sandbox's own overlayfs /tmp: the kernel's in-memory path, no FUSE. It is the ceiling for this host, not a peer:
No FUSE hop
The reference runs inside the kernel. Every LayerFS operation is a FUSE request to its daemon, a round trip every FUSE filesystem pays.
Writes reach the daemon
Kernel writeback caching is off under the FUSE contract, so each buffered write reaches LayerFS; the reference only copies into page cache.
Every change is recorded
LayerFS records each change so a Commit can capture it and mount it again later. The reference keeps nothing once the container goes.
Buffered writes are the widest gap
The kernel path finishes a buffered 4 KiB write by copying into page cache; with writeback off, every FUSE write, LayerFS’s and the baseline’s alike, is a round trip to a server.
A ceiling, not a peer
Ratios show the cost of those properties against the fastest local path on this host. The like-for-like comparison is the FUSE baseline, libfuse’s passthrough_ll, measured in the same run.
Job by job, all three arms
Bandwidth per job as recorded, each row on its own scale, with IOPS and completion latency (LayerFS / FUSE baseline / kernel overlayfs).
seq-write
write 1M · end_fsync=1 · 1g
514 MB/s1,669 MB/s3,258 MB/sIOPS 490 / 1,592 / 3,108
p50 1.4 ms / 465 µs / 232 µs
p99 13.2 ms / 3.4 ms / 1.0 msseq-read
read 1M · 1g
5,031 MB/s6,228 MB/s6,111 MB/sIOPS 4,798 / 5,940 / 5,828
p50 167 µs / 149 µs / 153 µs
p99 660 µs / 578 µs / 444 µsrand-write
randwrite 4k · 512m
33.1 MB/s82.0 MB/s2,595 MB/sIOPS 8,087 / 20,017 / 633,475
p50 79 µs / 38 µs / 1.2 µs
p99 774 µs / 235 µs / 3.2 µsrand-read
randread 4k · 512m
3,000 MB/s2,128 MB/s2,547 MB/sIOPS 732,447 / 519,465 / 621,793
p50 1.0 µs / 1.1 µs / 1.2 µs
p99 4.5 µs / 32 µs / 5.2 µsrand-read-4j
randread 4k × 4 jobs · 512m
12,573 MB/s10,793 MB/s10,682 MB/sIOPS 3,069,486 / 2,635,110 / 2,607,789
p50 1.0 µs / 1.1 µs / 1.3 µs
p99 1.5 µs / 1.8 µs / 1.8 µsrandrw-70-30 (read)
randrw 4k · 512m
102 MB/s45.5 MB/s1,622 MB/sIOPS 24,786 / 11,117 / 395,877
p50 1.8 µs / 51 µs / 1.4 µs
p99 11 µs / 264 µs / 4.9 µsrandrw-70-30 (write)
randrw 4k · 512m
43.6 MB/s19.5 MB/s695 MB/sIOPS 10,641 / 4,769 / 169,660
p50 74 µs / 44 µs / 1.5 µs
p99 322 µs / 181 µs / 5.5 µssync-write
write 4k · fsync=1 · 64m
58.0 MB/s8.39 MB/s11.5 MB/sIOPS 14,152 / 2,049 / 2,800
p50 62 µs / 32 µs / 3.2 µs
p99 185 µs / 140 µs / 13 µsrand-write-direct
randwrite 4k · O_DIRECT · 512m
49.6 MB/sFAIL70.3 MB/sIOPS 12,104 / — / 17,162
p50 66 µs / — / 46 µs
p99 371 µs / — / 157 µsrand-read-direct
randread 4k · O_DIRECT · 512m
54.4 MB/s36.6 MB/s70.7 MB/sIOPS 13,287 / 8,931 / 17,259
p50 68 µs / 77 µs / 49 µs
p99 122 µs / 322 µs / 163 µs
What it says
Mixed and direct I/O lead
Against the FUSE baseline, LayerFS is ahead on the 70/30 mixed job and on O_DIRECT random reads; on the mixed job its reads came from page cache while the baseline’s went to its server.
Streaming writes trail
Sequential and buffered random writes run below the baseline. LayerFS also records each write for the next Commit, work the baseline does not do; this run does not separate that cost.
fsync by profile
A Disposable Workspace promises no durability, so its fsync returns at once (p50 under 1 µs) where the baseline flushes to its backing. Shown, not counted.
A sibling container
A Sandbox cannot host a second FUSE mount (no-new-privileges, no user namespaces), so passthrough_ll runs in a sibling container from the same image, on the same VM and kernel; the tool runs as the same uid 501.
Its own defaults
passthrough_ll runs as root with no credential switch, up to 10 threads and a 1.0 s cache timeout. It keeps nothing beyond the directory: no recording, no Commit.
Read with care
One 20 s sample per job and arm at host load 6.50-19.89 (1 min). Finished files were removed from the two reference arms to keep the VM's page cache from overflowing. Docker Desktop on an arm64 Mac, LayerFS at main e5c7aaae05. An earlier two-arm run is in the data folder.
Data: benchmark/data/fio/v1.0.0/three-arm/ in the LayerFS repository (every job, ratios, the Commit, environment, receipts with fio's JSON, and the run record).