Benchmarks


jerboa-bench compares Jerboa hypervisor backends with each other and with Docker. It is built to give numbers you can defend:

Running it

go build -o dist/jerboa-bench ./cmd/jerboa-bench

# Linux: two daemons with separate state, one network per daemon.
HOME=/tmp/bq jerboad --host unix:///tmp/bq.sock &
HOME=/tmp/bf jerboad --host unix:///tmp/bf.sock --hypervisor firecracker &
HOME=/tmp/bq jerboa --host unix:///tmp/bq.sock network create benchq --subnet 10.231.0.0/24
HOME=/tmp/bf jerboa --host unix:///tmp/bf.sock network create benchfc --subnet 10.232.0.0/24

dist/jerboa-bench --jerboa dist/jerboa \
  --runtime qemu=jerboa,host=unix:///tmp/bq.sock,network=benchq,store=/tmp/bq/.jerboa/images \
  --runtime fc=jerboa,host=unix:///tmp/bf.sock,network=benchfc,store=/tmp/bf/.jerboa/images,layout=compact \
  --runtime docker=docker \
  --runs 30 --warmup 3 --idle-sample 10s --load-duration 10s --load-direct \
  --out bench.json

The run writes bench.json (metadata, image sizes, summaries and every run), bench.csv (one row per run) and prints a summary table. The nightly image-benchmarks job runs the same harness on the KVM runner and uploads these files as artifacts.

Runtime options

--runtime label=kind[,key=value...] is repeatable. kind is jerboa or docker.

OptionApplies toMeaning
hostjerboaDaemon endpoint
networkjerboaNetwork to join (required on Linux for port publishing)
storejerboaThe daemon’s --store, used to measure image sizes (default ~/.jerboa/images)
layoutjerboastandard or compact
binjerboaA different jerboa CLI for this runtime
imagebothUse a prebuilt image instead of the test app (sizes and binary verification are skipped)
argsbothExtra, space-separated run flags, e.g. args=--disk-io-engine async or args=-e POSTGRES_HOST_AUTH_METHOD=trust

What the numbers mean

MetricJerboaDocker
create_msjerboa run returns (image resolved, boot disk cloned and verified, hypervisor launched)docker run -d returns
ready_msFirst 2xx from --ready (default http:/ready) through the published port, measured from the start of createSame
stop_ms / remove_msjerboa stop / jerboa rmdocker stop / docker rm
mem_*_mibResident memory of the hypervisor process (guest RAM it has touched plus VMM overhead)Container cgroup usage from docker stats
Image logicalDisk image sizedocker image inspect size
Image allocatedBlocks the disk image occupies on the host—
Image gzip / zstdCompressed disk imageCompressed docker save output

Memory figures measure different boundaries. A VM’s resident set includes its guest kernel and page cache, while a container’s cgroup excludes the shared host kernel. Report both definitions together, not as a single “memory” column.

On macOS, Docker Desktop runs containers inside a Linux VM, and Jerboa’s native backends are a development preview. Publish comparisons from Linux hosts.

Service workloads

HTTP and published-port overhead

--load-duration runs a closed-loop HTTP load test (--load-concurrency keep-alive connections against --load-path) after each measured run is ready. With --load-direct on Linux, it also loads the guest or container IP directly. The difference between load_published_* and load_direct_* is the cost of port publishing: Jerboa’s userspace forwarder versus Docker’s proxy or NAT.

Databases

--load-cmd replaces the HTTP test with any command. {host} and {port} are substituted, and --load-metric extracts the result from the command’s output. For example, PostgreSQL with pgbench:

dist/jerboa-bench --jerboa dist/jerboa --guest-port 5432 --ready tcp \
  --runtime pg=jerboa,host=unix:///tmp/bq.sock,network=benchq,image=postgresql:latest \
  --runtime docker=docker,image=postgres:11,args=-e POSTGRES_HOST_AUTH_METHOD=trust \
  --runs 10 --warmup 1 \
  --load-cmd 'pgbench -h {host} -p {port} -U postgres -i -s 10 postgres >/dev/null && pgbench -h {host} -p {port} -U postgres -c 8 -j 4 -T 30 postgres'

A TCP probe can succeed on a published port before the database accepts queries, so keep the initialization step (pgbench -i) in the command.

Profiling storage