From 305df726a8e3f3caef9118ebe697a827754d6362 Mon Sep 17 00:00:00 2001 From: nashzhou Date: Wed, 14 Oct 2026 14:51:31 +0800 Subject: [PATCH] feat(metrics): close remaining pause/resume stage gaps After 0003/0004 the pause outer total still carried unattributed time at high concurrency. Cover the last uninstrumented segments so the outer stage roughly equals the sum of inner stages: - pause: prep_artifact (allocate_artifact_root), prep_detach (handle/route detach -- write-lock convoy candidate at high pause concurrency), dirty_ranges (FC dirty bitmap fetch between vm_state and mem_convert). - resume: vm_resume (FC PATCH /vm letting vCPUs run, the tail of start_resume after load_snapshot) and wait_ready (envd readiness poll + notify_sandbox_ready + envd init in launch_sandbox). The wait_ready operation label derives from the launch plan: "resume" for snapshot-sourced launches (shared with warm creates, like the other start_resume stages), "create" for fresh launches. Known-remaining uninstrumented slack: snapshot_to_dir tail misc (mem_image.json write, manifest build -- expected milliseconds) and in-memory store ops. No behavior change; instrumentation only. Applies on top of 0003+0004. --- src/orchestrator/service.rs | 27 +++++++++++++++++++++++---- src/sandbox/firecracker/sandbox.rs | 6 ++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/orchestrator/service.rs b/src/orchestrator/service.rs index d2a7f85..39368aa 100644 --- a/src/orchestrator/service.rs +++ b/src/orchestrator/service.rs @@ -1466,7 +1466,13 @@ where // Allocate persistence space while the running handle and route are // still attached. Allocation does not mutate the backend, so failure // only needs to restore metadata and release the temporary image refs. - let artifact_root = match self.persister.allocate_artifact_root(&sandbox_id).await { + let artifact_root = match SandboxStageTimer::new("pause") + .time( + "prep_artifact", + self.persister.allocate_artifact_root(&sandbox_id), + ) + .await + { Ok(artifact_root) => artifact_root, Err(err) => { warn!(error = ?err, "failed to allocate paused sandbox artifact root"); @@ -1484,7 +1490,12 @@ where } }; - let (handle, removed_proxy_route) = self.detach_sandbox_handle_and_route(&sandbox_id).await; + let (handle, removed_proxy_route) = SandboxStageTimer::new("pause") + .time("prep_detach", async { + Ok::<_, anyhow::Error>(self.detach_sandbox_handle_and_route(&sandbox_id).await) + }) + .await + .expect("prep_detach cannot fail"); let Some(handle) = handle else { warn!("sandbox handle not found while pausing, removing from store"); @@ -2493,10 +2504,18 @@ where return Err(OrchestratorError::ShuttingDown); } - // Wait for the sandbox to be ready + // Wait for the sandbox to be ready. Snapshot-sourced launches are the + // resume path, so their readiness wait lands under operation="resume" + // alongside the start_resume stages (fresh launches report "create"). + let wait_ready_operation = match plan { + LaunchPlan::Resume(_) => "resume", + LaunchPlan::Create(_) => "create", + }; let wait_result = { let sandbox = handle.lock().await; - sandbox.wait_for_ready().await + SandboxStageTimer::new(wait_ready_operation) + .time("wait_ready", sandbox.wait_for_ready()) + .await }; if let Err(source) = wait_result { warn!(error = %format_args!("{source:#}"), "sandbox failed to become ready"); diff --git a/src/sandbox/firecracker/sandbox.rs b/src/sandbox/firecracker/sandbox.rs index 27712fd..8c0c97e 100644 --- a/src/sandbox/firecracker/sandbox.rs +++ b/src/sandbox/firecracker/sandbox.rs @@ -1367,7 +1367,9 @@ impl FirecrackerSandbox { // `vm_state.bin` now represents this paused VM state. Any later // error aborts this direct snapshot attempt and is propagated to the // lifecycle caller for recovery. - let dirty_ranges = self.fc_instance.get_dirty_memory_ranges().await?; + let dirty_ranges = stages + .time("dirty_ranges", self.fc_instance.get_dirty_memory_ranges()) + .await?; stages .time( "mem_convert", @@ -2329,7 +2331,7 @@ impl FirecrackerSandbox { .await .context("reconcile disk rate limiter on snapshot resume")?; - self.fc_instance.resume().await?; + stages.time("vm_resume", self.fc_instance.resume()).await?; debug!("sandbox restored from snapshot config"); Ok(()) -- 2.43.0