Skip to content

Benchmarks and Comparison

Karthik Vinayan edited this page Jun 24, 2026 · 1 revision

Benchmarks & Comparison

dcon runs every container in its own Apple container microVM. That buys stronger isolation and a tiny idle footprint, but a fresh microVM is slower to start than a shared-VM engine. dcon is ~12× lighter at idle, ships a ~5.3 MB CLI instead of a multi-hundred-MB app bundle, and with the Warm Pool starts faster than OrbStack while keeping per-container isolation. Cold start and cold pull are bounded by Apple's runtime, not by dcon.

All numbers below are measured on the real machine — Apple silicon (Mac16,12), macOS 26, Apple container 1.0.0 — against the docker engine installed on the same host (OrbStack). Reproduce with make bench.

At a glance

dcon at a glance: 92 MB idle, 5.3 MB CLI, per-container VM, 0 daemons

Idle engine memory: dcon 92 MB vs OrbStack 1094 MB vs Docker Desktop ~2000 MB

Container start: dcon warm pool 90 ms vs OrbStack 212 ms (shared VM) vs dcon cold 769 ms

Full numbers

Medians of 5 runs, this host. dcon = Apple container; docker = OrbStack 29.4.0.

metric dcon (Apple container) docker (OrbStack)
idle engine memory ~91–92 MB ~1004–1094 MB
CLI ~5.3 MB single static binary app bundle (100s of MB)
isolation model per-container microVM (stronger) shared Linux VM
background footprint launchd helper, on-demand persistent VM
container start — warm pool (run --rm alpine echo) ~90 ms, still per-container ~206–212 ms (shared VM)
container start — cold (fresh microVM) ~700–769 ms ~206–212 ms
cold pull alpine ~13 s¹ ~3 s

¹ network/registry/content-store bound (Apple's floor), not dcon overhead. See Limited by Apple below.

A few rows in plain English:

  • Idle memory is ~12× lighter than OrbStack. Apple's services idle at ~91–92 MB, and microVMs exist only while a container is up. OrbStack keeps a full Linux VM resident at ~1 GB the whole time; Docker Desktop is heavier still at ~2000 MB. So vs Docker Desktop the memory gap is roughly ~22×, not 12×.
  • Container start has two rows, on purpose. Cold (a brand-new microVM) is slower than a shared-VM engine, the cost of per-container isolation. The Warm Pool moves that boot off your critical path, and the resulting ~90 ms warm start beats OrbStack's ~212 ms by ~2.2× while every run still gets a pristine, never-reused VM. This is OrbStack's always-warm behavior on a per-container VM rather than a shared one.
  • Cold pull is slower: ~13 s vs ~3 s. This is Apple's content-store and the network, not Go. Details below.

Methodology

  • Host: Darwin arm64, Mac16,12, macOS 26. Apple container 1.0.0; OrbStack 29.4.0.
  • Sampling: 5 runs per metric, median reported. Headline asset values are rounded (e.g. warm 90 / OrbStack 212 / cold 769 ms in bench-startup.svg).
  • Images are pre-warmed before the start-latency runs, so the start numbers measure VM boot / exec, not a pull. The cold-pull row is measured separately on a cleared cache.
  • Pull concurrency: runs use dcon's default of 8 concurrent layer downloads.
  • Reproduce: make bench (drives scripts/bench.sh, writes scripts/bench-results.md). See scripts/bench-results.md in the repo for the raw table from the latest run.

Numbers move with the host, the image, network conditions, and the Apple container version. Treat them as orders of magnitude, not guarantees, and rerun make bench on your own machine.

The honest tradeoff — limited by Apple

dcon is a thin translation layer (see Architecture). It is not where the time goes, and the profiling shows it.

dcon adds ~zero overhead. Raw container run --rm alpine echo measures ~700 ms; dcon run … measures ~690 ms, identical within noise. The entire cold-start cost is Apple's per-container microVM boot, not dcon's Go. You cannot optimize dcon to make a cold container start meaningfully faster, because dcon is already free.

Where the ~700 ms cold start actually goes:

phase cost note
container create ~40 ms cheap; just sets up the container record
container start ~650 ms the boot: kernel + init + vminitd + network

Pre-creating containers does not help: the cost lives in start, the boot itself. And Apple's apiserver serializes VM boots: launching 4 container run -d concurrently is only ~11% faster than running them one at a time. You cannot parallelize the boot path. That serialization is also why pure-boot Compose stacks gain only modestly (~11–16%) from concurrency, while build/pull-heavy stacks gain a lot more (those steps are network/builder-bound, not boot-bound).

Cold boot is Apple's floor, and the warm pool is the way past it. The Warm Pool pays the ~650 ms boot ahead of time, in the background, and then execs your workload into an already-running VM. An exec into a live VM is ~60–90 ms, and that floor is itself set by the container CLI's own Swift startup (~70 ms), not by dcon. There is no further headroom to win there either.

Cold pull (~13 s) is network + content-store bound, also Apple's floor. Two caveats so nobody over-claims:

  • dcon raised the default layer-download concurrency from the backend's default of 3 to 8. That's the empirical knee; gains past 8 are under 5%. It's a real but modest knob, tunable via --max-concurrent-downloads or DCON_PULL_CONCURRENCY (clamped 1..32).
  • The large re-pull speedup you may notice is blob caching, not concurrency: rmi keeps the layer blobs, so a subsequent pull reuses them. Do not read the cold-pull number as "concurrency is slow" or the re-pull number as "concurrency is fast"; they're different mechanisms.

When dcon wins, and when it doesn't

you care about winner why
idle memory on a laptop dcon ~92 MB vs ~1 GB (OrbStack) / ~2 GB (Docker Desktop)
install/footprint dcon ~5.3 MB static binary, no desktop app, no always-on daemon
per-container isolation dcon every run gets its own microVM (cold and warm)
repeated short-lived --rm runs dcon (warm) ~90 ms, ~2.2× faster than OrbStack
one-off cold container start OrbStack shared VM is already warm; dcon pays a fresh ~700 ms boot
first-time cold image pulls OrbStack ~3 s vs ~13 s; bounded by Apple's content store

For mostly long-lived containers or warm, repeated runs, dcon is the lighter, better-isolated choice. For workloads dominated by one-shot cold boots or first-time pulls on a fresh cache, a shared-VM engine will feel snappier, and that gap is Apple's runtime, which dcon cannot erase.

See also

Clone this wiki locally