Benchmarks
fsx
sandbox.exec
inside a LayerFS v1.0.0 Workspace, and the same commands on the kernel's own overlayfs as the reference.
LayerFS against kernel overlayfs
vs kernel overlayfs- LayerFS
- core at main e5c7aaae05, through the JS SDK
- Tool
- xfstests ltp/fsx at 22348afe338c
- Reference
- kernel overlayfs, the same Sandbox's own /tmp (no FUSE)
- Host
- arm64 Mac · Docker Desktop, linux/arm64, 8 CPUs, 8.3 GB
- Load
- 7.5–14.9 (1 min)
Verdict
14 / 14 PASS
3.06 M operations checked · 0 data or size miscompares
files from 256 KiB to 64 MiB · mapped, buffered and direct I/O
14 / 14 PASS
same commands, same Sandbox, the container's overlayfs /tmp
Every variant, both seeds
Seven fsx configurations, seeds 1 and 2, each run once per arm. PASS is fsx's own "All operations completed A-OK" with exit 0.
What fsx could exercise
fsx probes optional operations at start and turns off any the filesystem refuses. Reads, writes, mapped reads and writes, truncates and direct I/O ran on both arms. These are the optional ones:
Outside LayerFS's FUSE surface, by design
No extended attributes, fallocate, ioctl, copy_file_range, locks or lseek; the kernel falls back or returns EOPNOTSUPP. Left unimplemented on purpose: no FUSE capability for them is requested. So fsx turned these off on LayerFS. layerfs-fuse/src/operations/unsupported.rs
- fallocate(0)
- fallocate(KEEP_SIZE)
- fallocate(PUNCH_HOLE|KEEP_SIZE)
- fallocate(ZERO_RANGE)
- fallocate(COLLAPSE_RANGE)
- fallocate(INSERT_RANGE)
Refused on both
The container's overlayfs refuses these too, so they say nothing about LayerFS.
- fallocate(UNSHARE_RANGE)
- fallocate(WRITE_ZEROES)
- clone range
- dedupe range
- exchange range
- dontcache IO
- atomic writes (needs -Z)
- atomic writes (IO stack)
Since the v0.1.6 report
Issue #361 reported FUSE failures on v0.1.6. fsx shows where v1.0.0 stands on each.
How it ran
Only through the JS SDK
Every fsx run is a sandbox.exec as the Sandbox's user (501), in the mounted Workspace and then in /tmp of the same container.
- project.init(a seed folder)the Store
- sandbox.create("bench", image)fsx built in, pinned by digest
- branch.fork("bench", "main")its own Branch
- sandbox.mount("bench", "bench")/workspaces/1
- sandbox.exec(× 28 + read-back)one fsx run each
- sandbox.commit(after all cases)everything fsx left
- sandbox.unmount(…, then close)
Then a Commit
After all 14 LayerFS runs, one sandbox.commit captured every file fsx left behind.
457 ms
166.7 MB logical · 15.3 MB newly stored
Speed, indicative only
fsx is a correctness tool; its pace is incidental. ops/s is Σ ops ÷ Σ fsx wall time over both seeds, one sample each on a loaded host.
Read with care
One sample each
Each variant, seed and arm ran once. Host load was 7.45-14.87 (1 min); seeds on one arm differ as much as some arm pairs.
Not exercised
fsx’s AIO, io_uring and log-writes modes were not run; fallocate ops were off on LayerFS, which does not serve them by design.
Warm caches
fsx reads what it just wrote. Nothing here is a cold read.
This host
Docker Desktop on an arm64 Mac, LayerFS at main e5c7aaae05, Disposable Store. Not a native Linux qualification.
Data: benchmark/data/fsx/v1.0.0/ in the LayerFS repository (results, environment, raw receipts and the run record).