perf(sandbox): quiet microVM console + reconfig latency attribution + resolv on tmpfs (round 2) - #558
Conversation
Every boot printk on the FC serial console is an MMIO exit, doubled by nesting; the stock CI kernel logs hundreds of lines. Silencing the console cuts the sandbox cold boot's in-guest time roughly in half. Measured on the sandbox_coldstart probe (M5 Max, VZ): create -> first exec p50 2.71 s -> 1.37 s networked, 2.65 s -> 1.10 s no-network; guest uptime at first exec 1.68 s -> 0.64-0.87 s. Restore path unaffected.
The restore completion log showed guest_cfg as one opaque ~114 ms block. Split it three ways: sync_clock/reconfigure_network log connect vs frame RTT host-side, and the net-reconfig MSG_EXIT payload now carries six u32 millis (four per-ioctl, resolv.conf write, whole handler) that the host logs on arrival — old hosts read only the leading exit code, so the extension is compatible both ways. The guest handler also replies before its console eprintln: /dev/console is the FC serial device written byte-by-byte through nested MMIO exits, and the log line was serialized ahead of the response. Attribution result (M5 Max, VZ): the four ioctls cost ~10 ms; the resolv.conf write costs 27-35 ms — the first write into the clone's fresh dm-snapshot pays a synchronous CoW exception through the nested ext4 -> virtio-blk -> dm -> loop -> Btrfs stack. That write is the next CORE-75 target (resolv.conf on tmpfs).
The post-restore net reconfig rewrites /etc/resolv.conf, and the clone's first write into its fresh dm-snapshot pays a synchronous CoW exception through the nested ext4 -> virtio-blk -> dm -> loop -> Btrfs stack — measured at 27-35 ms of the reconfig handler's 37-52 ms. Both template builders now bake /etc/resolv.conf as a symlink to /run/resolv.conf and vm-agent mounts /run as tmpfs, so every DNS rewrite (boot setup_dns, restore reconfig) lands in memory; the existing template freshness keys (vm-agent hash) roll the change out automatically. Old templates with a regular resolv.conf keep today's behavior. Measured: reconfig handler 37-52 -> 12-19 ms (resolv step 27-35 -> 3-9), restore RPC p50 243 -> 215 ms, restore -> first exec p50 287 ms.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Greptile SummaryThe PR reduces sandbox cold-start and post-restore latency while adding detailed reconfiguration timing attribution.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| guest/arcbox-agent/src/config.rs | Adds the quiet kernel argument to reduce serial-console overhead during microVM boot. |
| guest/arcbox-agent/src/rootfs_builder.rs | Makes /etc/resolv.conf point into /run for both default and injected guest root filesystems. |
| tests/e2e/tests/sandbox_coldstart.rs | Ensures at least one benchmark iteration and bounds execution-stream draining with a deadline. |
| virt/arcbox-vm/src/bin/vm-agent.rs | Adds per-step reconfiguration timing payloads, mounts /run as tmpfs, and centralizes child registration with reaper notification. |
| virt/arcbox-vm/src/vsock.rs | Logs connection and frame latency separately and parses the extended reconfiguration timing payload. |
| virt/arcbox-vm/src/sandbox/boot.rs | Raises hard-link fallback logging to warning level. |
| xtask/src/commands/e2e.rs | Prebuilds the sandbox binaries when running the cold-start end-to-end test. |
Sequence Diagram
sequenceDiagram
participant H as Host
participant A as vm-agent
participant N as Guest network stack
participant R as /run tmpfs
H->>A: Connect over vsock
H->>A: Net-reconfig frame
A->>N: Address/netmask/route ioctls
A->>R: Write resolv.conf
A-->>H: MSG_EXIT + six u32 timing values
H->>H: "Parse and log *_us timing split"
Reviews (4): Last reviewed commit: "fix(sandbox): address the round-1/2 revi..." | Re-trigger Greptile
|
No fix pushed — the failing check suite is not a build or test failure. Diagnosis. Check suite Current head Independent verification. Since CI never exercised the branch, I ran the reproducible pieces locally (Linux runner, so the macOS
The only clippy warnings I found in Working tree is clean; no commits were made.
|
There was a problem hiding this comment.
ℹ️ Nothing blocking here — a couple of small things worth tightening.
Reviewed changes
quietadded to the sandbox microVM boot args, plus/runtmpfs and an/etc/resolv.conf → ../run/resolv.confsymlink baked into both rootfs template builders, keeping the post-restore DNS rewrite off the dm-snapshot CoW path.net_reconfig::applynow returns per-step timings;handle_net_reconfigappends sixu32 LEvalues to theMSG_EXITreply (32 bytes) and writes the reply before the console log; the host parses and logs the split alongside a new connect-vs-frame RTT breakdown.register_childextracted from two duplicated insert+notify sites; jailer hard-link fallback promoteddebug!→warn!.- Harness:
.max(1)floor onARCBOX_COLDSTART_ITERS, deadlined attach drain, andsandbox_coldstartadded to the xtask prebuild arm.
I checked the things most likely to bite and they hold up:
MSG_EXITwidening is compatible both directions. New host + old 4-byte agent →ReconfigTimings::parsereturnsNoneviapayload.get(8..32)?and the timing log is skipped. Old host + new 32-byte agent → readspayload[..4]and ignores the tail;read_frameconsumes the exact declared length either way.- The new symlink is never dangling in the default template.
build_default_rootfsalready creates/runas a real directory in its skeleton list, so an agent that doesn't mount the tmpfs just writes/run/resolv.confon ext4 — the perf win is lost, DNS is not. Andmount_filesystems()runs beforesetup_dns(), so the ordering is right. quietdoesn't cost observability.serial_outis never set in the sandbox boot path, so guest console output is discarded in production regardless;firecracker.logis Firecracker's own JSON logger, not guest serial; readiness comes fromSandboxEventKind::Readyover the event stream, not a console grep. Panics andinit=exec failures still print, and verbose args stay reachable at runtime viaARCBOX_VMM_CONFIG.- The xtask prebuild arm matches
build_binaries()packages and profiles exactly, which is whatsandbox_coldstart.rscalls — no stale-binary path underSKIP_BUILD. - The
.max(1)floor is a real fix, not defensive padding:report()doesready.split_first().expect("at least one iteration").
ℹ️ Default-rootfs replacement doesn't consult the snapshot pin set
Not introduced by this PR, but this PR makes it reachable for every upgrading user, so it seems worth naming rather than leaving implicit.
The Docker layer cache is careful here: sweep_superseded takes pinned_rootfs_paths() and spares any image that is a live dm-snapshot origin. The default rootfs has no equivalent guard — ensure_default_rootfs renames the freshly built image over the fixed /var/lib/arcbox/sandbox/rootfs.ext4, gated only by the mtime check in is_default_rootfs_fresh, with no pin consultation. Meanwhile checkpoint_sandbox records that same path as a snapshot's rootfs_path.
This PR changes the baked layout of that image and (via the newer vm-agent binary) guarantees the mtime check fires on the first post-upgrade run, so any pre-existing checkpoint whose origin is the default rootfs gets its backing file swapped underneath it. Whether that matters depends on how long checkpoints are expected to outlive an upgrade — if the answer is "they aren't", this is a non-issue and worth a one-line comment saying so.
Technical details
ROOTFS_CACHE_DIR(rootfs_builder.rs) andSANDBOX_DATA_DIR(config.rs) are both/var/lib/arcbox/sandbox, so cached and default images share a directory.pinned_rootfs_paths()(checkpoint.rs) is consumed only bysweep_superseded;ensure_default_rootfsnever sees it.is_superseded_imageonly matches therootfs-prefix, sorootfs.ext4is never swept — but it is overwritten in place by therename, which is the same outcome for a pinned origin.checkpoint_sandboxsetsrootfs_path: Some(rootfs_path)unconditionally, including for default-rootfs sandboxes.
ℹ️ Nitpicks
virt/arcbox-vm/src/vsock.rs— the 32-byte layout is now hand-encoded in three independent places: the agent's writer,ReconfigTimings::parse, and the test's explicit "layout mirror". Reordering the agent'stimingschain would keep the test green while the host logs mislabeled fields. A shared encode/decode pair (or having the test call the real writer) would close that.guest/arcbox-agent/src/rootfs_builder.rs—if tokio::fs::create_dir_all(&etc).await.is_ok()drops the failure silently, while the siblingsymlinkfailure right below it warns. Same consequence for the caller (no symlink, writes hit the CoW device), so it'd be nice if it were equally visible.virt/arcbox-vm/src/bin/vm-agent.rs— the comment on the reordering says the log goes through/dev/consoleand serial MMIO. As PID 1 launched viainit=, the agent's fd 2 is whatever Firecracker handed it, not an open of/dev/console. The reordering is still the right call; the stated mechanism is just a little off.
Claude Opus | 𝕏
1498f4f to
11e5218
Compare
|
This run croaked 😵 The workflow encountered an error before any progress could be reported. Please check the link below for details. |
- probe: floor ARCBOX_COLDSTART_ITERS at 1 (report assumed a sample) and deadline the attach drain so a wedged exec fails the run with forensics instead of hanging it - xtask: widen the sandbox prebuild arm to sandbox_coldstart (same build_binaries recipe), so --repeat runs stop rebuilding every pass - vm-agent: fold registry insert + reaper wakeup into register_child so a future spawn site cannot forget the notify; report reconfig timings in microseconds (the ioctls land under a millisecond) - vsock: extract ReconfigTimings::parse with a layout unit test pinning the 32-byte reply shape; document the three MSG_EXIT payload shapes in both frame tables - boot: hard-link fallback logs at warn, so losing the restore fast path to a cross-device chroot is visible at default levels
11e5218 to
767d2d3
Compare
|
Your Claude subscription has hit its usage limit. It resets at 12:10am (UTC). Re-trigger Pullfrog after the reset, or add an Add repo secret → · Model settings → · Setup docs → · Ask in Discord →
|
|
No fix pushed — the failing check suite is not a build or test failure. Diagnosis. Check suite The repo's own Independent verification. Since Actions never exercised the branch, I ran the reproducible pieces on this Linux runner (the macOS
Working tree is clean; no commits were made. Re-triggering Pullfrog after the usage-limit reset (or adding an
|

Supersedes #556 (auto-closed by the #555 base-branch deletion, unreopenable after rebase — all its review threads were addressed in 02aaccc and are reflected here). Part of CORE-75, project Sandbox Cold Start. Now based directly on master.
What (4 commits)
quieton the microVM cmdline — boot printks over FC serial are nested-doubled MMIO exits. Measured: cold create→first-exec p50 2.71 s → 1.37 s (networked) / 2.65 → 1.10 s (no-network).ReconfigTimingswith a layout-pinning unit test; three MSG_EXIT payload shapes documented in both frame tables. Guest replies before its serial eprintln./etc/resolv.confwrite costs 27–35 ms (clone's first write pays a synchronous dm-snapshot CoW exception through the nested ext4→virtio-blk→dm→loop→Btrfs stack). Both template builders bake it as a symlink to/run/resolv.conf; vm-agent mounts/runtmpfs; auto-rollout via template freshness keys. Measured: reconfig handler 37–52 → 12–19 ms, restore RPC p50 243 → 215 ms, restore→first-exec p50 287 ms.xtaskprebuild arm forsandbox_coldstart, vm-agentregister_child(insert+wake fused), hard-link fallback logs at warn.Validation
fmt/clippy clean (host + musl bins);
cargo test -p arcbox-vm -p arcbox-agentgreen (incl. new layout test); probe green ×4 runs; full sandbox smoke green ×2 (covers docker-template conversion).