Skip to content

clone/restore execution pays the child VM's cgroup quota — provisioning work throttled under load #186

Description

@CMGS

Summary

Since #183 the VMM is spawned via CLONE_INTO_CGROUP directly into cocoon.slice/vm-<id>.scope, so everything the VMM does from its first instruction runs under the VM's Guaranteed-at-N policy (quota = N×period, burst 0) and inside the #185 fence. That includes the restore/clone-time memory loading:

  • copy mode: the eager multi-core memory copy executes inside the child scope's N-core quota;
  • mmap mode (default): the clone window itself is thin, but the deferred first-touch page faults pay inside the same quota after claim.

Restore/clone execution is operator/control-plane work — the per-VM policy is meant to bound the VM's workload, not the act of provisioning it. The docs already state this philosophy explicitly (docs/vm.md): "the fence bounds the VMs; the caller's own work (clone, restore, the API consumer) is deliberately not cocoon's to manage" — and warn that AllowedCPUs=15 "would confine clone's multi-core memory restore to one core". The implementation currently does exactly that confinement for the VMM-side half of restore, via the child's own scope.

Measured

16-core bare-metal host (AMD 9700X), CH lane, 1-vCPU/512M guests, 20-VM CPU-burn storm (each guest spinning its vCPU), sequential timed clones from one snapshot, n=12 per cell, quiet controls taken. A/B/C = pre-cgroup master (07f1d69) / 3542c8a scopes only / 3542c8a + cgroup_cpus=0-14:

clone p50/P90/max (ms) 07f1d69 scopes only scopes + fence
--restore-mode copy 390 / 530 / 547 330 / 609 / 717 516 / 1032 / 1348
mmap (default) 98 / 169 / 216 155 / 334 / 463 114 / 198 / 230

Copy-mode P90 roughly doubles once the child scope + fence apply — the eager copy that wants N cores gets exactly 1 core of quota with burst 0, placed inside the saturated fenced set. Quiet-host clones are unaffected (quota not binding). For contrast, the same round measured the fence's intended win on control-plane ops: vm list under the same storm went 62/133/147 → 5/5/5 p50/P90/max — the mechanism works as designed for steady-state isolation; it is specifically the provisioning window that lands on the wrong side of the boundary.

Options

  1. Spawn the VMM outside vm-<id>.scope (parent slice or a transient provisioning scope) and migrate it into its scope once restore completes / the VM reports ready — restore then runs as caller-side work, matching the documented contract. One controlled migration per boot; keeps CLONE_INTO_CGROUP semantics for the steady state.
  2. Keep CLONE_INTO_CGROUP but hold cpu.max=max during the restore window and arm Guaranteed-at-N at ready. Simpler; restore still respects the fence's placement, only the quota is deferred.
  3. At minimum, document the copy-mode × Guaranteed-at-N interaction as a known caveat for dense hosts.

Option 1 also covers mmap's deferred first-touch cost only if migration happens after warm-up, which it can't reasonably — so for mmap the residual is inherent and worth a doc note either way.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions