Benchmarks

fio

The standard I/O workload tool: sequential and random reads and writes, buffered and direct, one job with an fsync after every write, 20 seconds each. Every job runs in a LayerFS v1.0.0 Workspace through sandbox.exec, on a FUSE baseline (libfuse's passthrough_ll), and on the kernel's own overlayfs.

LayerFS against FUSE baseline

vs FUSE baseline
KindPerformancedata I/Oindustry standard
LayerFSv1.0.0
Ran on
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

LayerFS v1.0.0

9 / 9 PASS

every LayerFS job, O_DIRECT included · the FUSE baseline failed rand-write-direct

one Commit of the files fio left

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.

  1. seq-write0.31×514 MB/s / 1,669 MB/s
  2. seq-read0.81×5,031 MB/s / 6,228 MB/s
  3. rand-write0.40×33.1 MB/s / 82.0 MB/s
  4. rand-read1.41×page cache on every arm
  5. rand-read-4j1.16×page cache on every arm
  6. randrw-70-30 (read)2.23×102 MB/s / 45.5 MB/s
  7. randrw-70-30 (write)2.23×43.6 MB/s / 19.5 MB/s
  8. sync-write6.91×fsync: baseline flushes, Disposable does not
  9. rand-write-direct—baseline failed (EINVAL)
  10. rand-read-direct1.49×54.4 MB/s / 36.6 MB/s
◀ FUSE baseline fasterLayerFS faster ▶LayerFS ÷ baseline bandwidth, log scale to ±4×

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).

  1. seq-write

    write 1M · end_fsync=1 · 1g

    514 MB/s1,669 MB/s3,258 MB/s

    IOPS 490 / 1,592 / 3,108
    p50 1.4 ms / 465 µs / 232 µs
    p99 13.2 ms / 3.4 ms / 1.0 ms

  2. seq-read

    read 1M · 1g

    5,031 MB/s6,228 MB/s6,111 MB/s

    IOPS 4,798 / 5,940 / 5,828
    p50 167 µs / 149 µs / 153 µs
    p99 660 µs / 578 µs / 444 µs

  3. rand-write

    randwrite 4k · 512m

    33.1 MB/s82.0 MB/s2,595 MB/s

    IOPS 8,087 / 20,017 / 633,475
    p50 79 µs / 38 µs / 1.2 µs
    p99 774 µs / 235 µs / 3.2 µs

  4. rand-read

    randread 4k · 512m

    3,000 MB/s2,128 MB/s2,547 MB/s

    IOPS 732,447 / 519,465 / 621,793
    p50 1.0 µs / 1.1 µs / 1.2 µs
    p99 4.5 µs / 32 µs / 5.2 µs

  5. rand-read-4j

    randread 4k × 4 jobs · 512m

    12,573 MB/s10,793 MB/s10,682 MB/s

    IOPS 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 µs

  6. randrw-70-30 (read)

    randrw 4k · 512m

    102 MB/s45.5 MB/s1,622 MB/s

    IOPS 24,786 / 11,117 / 395,877
    p50 1.8 µs / 51 µs / 1.4 µs
    p99 11 µs / 264 µs / 4.9 µs

  7. randrw-70-30 (write)

    randrw 4k · 512m

    43.6 MB/s19.5 MB/s695 MB/s

    IOPS 10,641 / 4,769 / 169,660
    p50 74 µs / 44 µs / 1.5 µs
    p99 322 µs / 181 µs / 5.5 µs

  8. sync-write

    write 4k · fsync=1 · 64m

    58.0 MB/s8.39 MB/s11.5 MB/s

    IOPS 14,152 / 2,049 / 2,800
    p50 62 µs / 32 µs / 3.2 µs
    p99 185 µs / 140 µs / 13 µs

  9. rand-write-direct

    randwrite 4k · O_DIRECT · 512m

    49.6 MB/sFAIL70.3 MB/s

    IOPS 12,104 / — / 17,162
    p50 66 µs / — / 46 µs
    p99 371 µs / — / 157 µs

  10. rand-read-direct

    randread 4k · O_DIRECT · 512m

    54.4 MB/s36.6 MB/s70.7 MB/s

    IOPS 13,287 / 8,931 / 17,259
    p50 68 µs / 77 µs / 49 µs
    p99 122 µs / 322 µs / 163 µs

■ LayerFS■ FUSE baseline■ Kernel overlayfs

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).