Skip to main content
Fork removes the cost of starting an episode. Most of what is left in a Kubernetes episode is waiting — readiness probes, CrashLoopBackOff timers, controller reconcile ticks. A 3-node Ubuntu cluster is all-idle ~70% of the time and only 7–10% of its vCPUs are awake. k7d already owns the guest clock end to end (kvm-clock, no RTC, no NTP client, KVM_SET_CLOCK on every restore), so the same pause that makes a fork correct can also move every member’s clock by the same delta. Two mechanisms, one rule: forward only, lockstep only, whole-cluster pause or nothing — a declined warp is always correct.

The numbers

An 8.7-minute guest-time episode on a 3-node Ubuntu k3s cluster:

Lockstep jumps — warp_clock and auto_warp

warp_clock moves every live VM on one cluster bridge forward by delta_ms:
The whole cluster is paused for the write and resumed after it. A uniform jump is what etcd heartbeats, lease TTLs, and TLS skew checks tolerate; a skewed one is not. A warp that fails on one member rolls that member back and errors — all or none. Instead of telling the daemon “+90 s”, let it find the idle time itself:
Every reason a cycle declines to warp is a correct outcome; declining costs a sample, guessing costs correctness.
Caller contract: no guest action may be in flight during a warp. Daemon ops run under the VM registry lock the policy loop also takes, so they cannot overlap a jump. A client driving a member from outside the daemon — an agent exec straight over vsock — is invisible to that lock and must take a hold first:
Otherwise that guest sees its clock jump mid-syscall. Releasing a hold nobody took is an error, not a no-op.

Continuous dilation — dilation and set_dilation

Dilation makes every clock the guest can read run N× faster than wall time, for the whole life of the VM. It needs a small carried KVM patch on the host (per-VM continuous time dilation). The patch and the install/revert loop ship in the repo at utils/kvm-dilation/:
install.sh stops k7d, refuses the swap if another VM still holds /dev/kvm, and puts stock modules back if the patched pair fails to load. Ubuntu x86, root, and the running kernel’s linux-source / headers (pulled from Launchpad). A host without the patch fails VM creation for dilation > 1 instead of silently running at 1×. Lockstep jumps need no patch. Set it at creation — every member of a cluster is created from one VmConfig, so a cluster is dilated in lockstep by construction:
Change it live on a running cluster (the cluster is paused for the write; the kernel refuses the change while any vCPU is runnable):
Lowering the factor is not a rewind — the guests keep every nanosecond they have already been given; they only stop accumulating them so fast. Raising is the same write in the other direction.

Forks and dilation

A fork lands on the source’s clock and inherits the source’s factor unless told otherwise:
So one ×1 source tree serves every mode: fork some children at ×8 for cheap exploration and keep others at ×1 for a faithful control. tree_nodes reports each live node’s factor in live_dilation; fork responses carry dilation.

Why N=8 and not 16

Compression is exactly N through 16 — but the fidelity cost is a curve, not a cliff. Extra liveness-probe failures across N ∈ went 0 / 0 / 0 / 3 / 19 / 32, and in-guest churn rounds collapsed 110 → 7. The host-side reading that moved with the damage is busy-phase mean awake vCPUs: at 6 of 6 there is no idle left to sell. That is the signal an adaptive policy should watch — not probe failures, which arrive through the guest’s API server, the exact thing dilation is starving.

What is and is not compressible

  • Compressible: guest-side waiting — timers, backoffs, probe periods, lease TTLs, reconcile intervals.
  • Not compressible: compute. A dilated guest still takes the same wall time to fsync or serve a request, so from the guest’s point of view those operations look N× slower. That is the fidelity cost above, and it is why the honest default is a jump policy at zero cost, with dilation opt-in per tree.
  • Not touched: the source’s clock when you fork. Warp and dilation apply to the cluster you name; siblings on other bridges are unaffected.