Motivation
Performance is one of the primary goals of elfuse. While functional correctness is verified through automated testing, continuous performance evaluation is equally important to detect regressions and quantify improvements over time.
This proposal introduces a lightweight benchmark suite that can be executed automatically in CI/CD and provides a consistent basis for comparing elfuse against native Linux and OrbStack.
Objectives:
- Detect performance regressions in pull requests.
- Provide reproducible measurements across releases.
- Keep CI execution time short.
- Focus on workloads representative of Linux application execution.
Benchmark Strategy
Two complementary tiers:
- Tier 1: Microbenchmarks using lmbench to isolate low-level operating system overheads.
- Tier 2: Application Benchmarks using widely adopted command-line tools to measure real-world developer workflows.
Tier 1: lmbench Microbenchmarks
Rather than adopting large suites such as SPEC CPU or Phoronix Test Suite, this proposal selects three focused lmbench benchmarks representing the most critical execution paths of elfuse.
| Benchmark |
Purpose |
Relevance |
lat_syscall |
Measure system call latency |
Evaluates the overhead of the Linux ABI and syscall forwarding path. |
lat_proc exec |
Measure process startup latency |
Evaluates ELF loading, dynamic linking, memory mapping, and process initialization. |
lat_fs |
Measure filesystem metadata latency |
Evaluates pathname translation and filesystem-intensive workloads. |
lat_syscall
Measures the latency of fundamental system calls. Recommended operations: null, read, write, stat, open. These represent the basic cost of entering the Linux execution environment and are exercised by nearly every Linux application.
lat_proc exec
Measures end-to-end process startup latency via exec(). For elfuse, it covers nearly the entire execution path: ELF parsing, program loading, dynamic linker initialization, memory mapping, initial process setup, and process termination. Primary indicator of Linux application startup performance.
lat_fs
Measures filesystem metadata operations (file creation, deletion, directory traversal). Metadata-intensive workloads are common in Git, Make, CMake, package managers, and shell utilities, so lat_fs approximates many software development workloads.
Tier 2: Application Benchmarks
Microbenchmarks explain where time is spent; developers ultimately care about application performance. The suite includes representative command-line tools exercising common Linux development workflows.
| Tool |
Primary workload |
Primary subsystem |
python3 -c pass |
Process startup |
ELF loader, dynamic linker, interpreter initialization |
git status |
Filesystem metadata |
open(), stat(), readdir() |
rg (ripgrep) |
Large-scale source search |
mmap(), read(), page cache |
zstd |
Compression |
CPU computation and filesystem I/O |
make (small project) |
Software build |
Process creation, filesystem access, compiler invocation |
These were selected because they are representative of daily Linux developer workflows, small enough to execute in CI, stable and reproducible, and portable across native Linux, OrbStack, and elfuse.
CI/CD Integration
The complete suite should run for every pull request:
Build elfuse
│
Run lmbench benchmarks
│
Run application benchmarks
│
Collect benchmark results
│
Generate JSON report
│
Compare with baseline
│
Upload artifacts
Expected execution time remains only a few minutes.
Result Format
Benchmark results exported as structured JSON to simplify regression analysis:
{
"lmbench": {
"lat_syscall": { "null": 0.23, "open": 1.98, "stat": 2.45 },
"lat_proc": { "exec": 705 },
"lat_fs": { "create": 47, "delete": 34 }
},
"applications": {
"python_startup_ms": 24.1,
"git_status_ms": 132.7,
"ripgrep_ms": 218.4,
"zstd_ms": 645.8,
"make_ms": 1038.2
}
}
Comparison Targets
Compare three execution environments: Native Linux (baseline), OrbStack, and elfuse. Each benchmark reports both absolute time and the ratio relative to native Linux.
| Benchmark |
Native Linux |
OrbStack |
elfuse |
lat_proc exec |
520 µs |
730 µs |
680 µs |
lat_syscall(open) |
1.4 µs |
1.8 µs |
2.0 µs |
lat_fs(create) |
41 µs |
46 µs |
44 µs |
python3 -c pass |
21 ms |
26 ms |
24 ms |
git status |
118 ms |
126 ms |
121 ms |
rg |
205 ms |
214 ms |
208 ms |
zstd |
630 ms |
651 ms |
642 ms |
make |
1.02 s |
1.08 s |
1.04 s |
(Numbers above are illustrative placeholders, not measured results.)
Implementation Plan
Concrete, self-contained tasks. Each is independently mergeable and grounded in the current tree (tests/bench-*, tests/test-matrix.sh, tests/fetch-fixtures.sh, .github/workflows/main.yml).
Constraint: where benchmarks can run
elfuse requires the Hypervisor.framework entitlement, so any benchmark that executes a guest through elfuse only runs on the existing [self-hosted, macOS, arm64] runner (the runtime-macos job in main.yml), not on GitHub-hosted ubuntu-24.04 / macos-15. Consequence: native-Linux and OrbStack baselines cannot be produced inside GitHub-hosted CI. They are captured manually on a reference host and checked in as static baseline JSON; CI measures only the elfuse-aarch64 (and, where available, qemu-aarch64) columns and compares against the checked-in baseline.
Task 1: Vendor/fetch benchmark guest binaries
Task 2: Benchmark runner + JSON emitter
Task 3: Baseline + regression comparison
Task 4: CI/CD integration
Acceptance criteria
Motivation
Performance is one of the primary goals of elfuse. While functional correctness is verified through automated testing, continuous performance evaluation is equally important to detect regressions and quantify improvements over time.
This proposal introduces a lightweight benchmark suite that can be executed automatically in CI/CD and provides a consistent basis for comparing elfuse against native Linux and OrbStack.
Objectives:
Benchmark Strategy
Two complementary tiers:
Tier 1: lmbench Microbenchmarks
Rather than adopting large suites such as SPEC CPU or Phoronix Test Suite, this proposal selects three focused lmbench benchmarks representing the most critical execution paths of elfuse.
lat_syscalllat_proc execlat_fslat_syscallMeasures the latency of fundamental system calls. Recommended operations:
null,read,write,stat,open. These represent the basic cost of entering the Linux execution environment and are exercised by nearly every Linux application.lat_proc execMeasures end-to-end process startup latency via
exec(). For elfuse, it covers nearly the entire execution path: ELF parsing, program loading, dynamic linker initialization, memory mapping, initial process setup, and process termination. Primary indicator of Linux application startup performance.lat_fsMeasures filesystem metadata operations (file creation, deletion, directory traversal). Metadata-intensive workloads are common in Git, Make, CMake, package managers, and shell utilities, so
lat_fsapproximates many software development workloads.Tier 2: Application Benchmarks
Microbenchmarks explain where time is spent; developers ultimately care about application performance. The suite includes representative command-line tools exercising common Linux development workflows.
python3 -c passgit statusopen(),stat(),readdir()rg(ripgrep)mmap(),read(), page cachezstdmake(small project)These were selected because they are representative of daily Linux developer workflows, small enough to execute in CI, stable and reproducible, and portable across native Linux, OrbStack, and elfuse.
CI/CD Integration
The complete suite should run for every pull request:
Expected execution time remains only a few minutes.
Result Format
Benchmark results exported as structured JSON to simplify regression analysis:
{ "lmbench": { "lat_syscall": { "null": 0.23, "open": 1.98, "stat": 2.45 }, "lat_proc": { "exec": 705 }, "lat_fs": { "create": 47, "delete": 34 } }, "applications": { "python_startup_ms": 24.1, "git_status_ms": 132.7, "ripgrep_ms": 218.4, "zstd_ms": 645.8, "make_ms": 1038.2 } }Comparison Targets
Compare three execution environments: Native Linux (baseline), OrbStack, and elfuse. Each benchmark reports both absolute time and the ratio relative to native Linux.
lat_proc execlat_syscall(open)lat_fs(create)python3 -c passgit statusrgzstdmake(Numbers above are illustrative placeholders, not measured results.)
Implementation Plan
Concrete, self-contained tasks. Each is independently mergeable and grounded in the current tree (
tests/bench-*,tests/test-matrix.sh,tests/fetch-fixtures.sh,.github/workflows/main.yml).Constraint: where benchmarks can run
elfuse requires the Hypervisor.framework entitlement, so any benchmark that executes a guest through elfuse only runs on the existing
[self-hosted, macOS, arm64]runner (theruntime-macosjob inmain.yml), not on GitHub-hostedubuntu-24.04/macos-15. Consequence: native-Linux and OrbStack baselines cannot be produced inside GitHub-hosted CI. They are captured manually on a reference host and checked in as static baseline JSON; CI measures only theelfuse-aarch64(and, where available,qemu-aarch64) columns and compares against the checked-in baseline.Task 1: Vendor/fetch benchmark guest binaries
lat_syscall,lat_proc,lat_fs) to the fixtures flow intests/fetch-fixtures.sh(same Alpine-package pattern already used for busybox/coreutils). Pin the package version and record the SHA.git,ripgrep(rg),zstd,make, and a Python interpreter. Where a static build is impractical, document the dynamic +--sysrootinvocation instead.git status/rg/maketargets (a small committed corpus undertests/bench-corpus/) so measurements are reproducible run to run../elfuse <fixture> --help(or equivalent) exits 0.Task 2: Benchmark runner + JSON emitter
tests/bench-suite.shthat runs the Tier-1 and Tier-2 workloads and writes one JSON document matching the schema in "Result Format". Reusetests/lib/test-runner.sh(run/run_check) so every invocation inherits the existingtimeout $TEST_TIMEOUTwrapping.BENCH_ENV=elfuse-aarch64|native|orbstack) so the same script produces every column. Reusedetect_x86_64_host_class/ the mode plumbing fromtests/test-matrix.shrather than duplicating host detection.make benchtarget (and a CI-scopedmake bench-ci) that builds the harness and runstests/bench-suite.sh, writingbuild/bench-results.json.Task 3: Baseline + regression comparison
scripts/bench-compare.py: takesbuild/bench-results.jsonand a checked-intests/bench-baseline.json, prints a per-metric ratio table, and exits non-zero when any metric regresses beyond a threshold (default: +20%, configurable via env). Reuse the CLI/reporting style ofscripts/check-syscall-coverage.py.tests/bench-baseline.jsoncaptured on the self-hosted runner (elfuse column) plus manually captured native-Linux and OrbStack columns on a documented reference host. Record host class / CPU / date in the file so stale baselines are visible.tests/READMEor the suite script header.Task 4: CI/CD integration
benchmarkleg to theruntime-macosmatrix in.github/workflows/main.yml(self-hosted arm64), gated the same way as the existing legs (github.repository == 'sysprog21/elfuse'), runningmake bench-cithenscripts/bench-compare.py.build/bench-results.jsonviaactions/upload-artifact@v7(mirror the existinginfer-*artifact step) with a short retention.bench-compare.pyin report-only mode (|| trueor acontinue-on-errorstep) for an initial settling period, then flip to hard-fail once the runner's variance is characterized. State the flip criterion in the workflow comment.runtime-macostimeout-minutesbudget.Acceptance criteria
make benchproduces valid JSON matching the documented schema on a dev machine.scripts/bench-compare.pycorrectly flags an injected 2x regression and passes on baseline.