Repository navigation
perf(hypervisor): move pause VM teardown off the pause critical path - #1731
Conversation
a3eddf8 to
fb8a84a
Compare
|
wait_notify(VmShutdown) after pause-to-snapshot is historical: returning before the VM was fully gone used to race host resources (TAP, and similar). That context is old — happy to re-evaluate whether teardown can stay async. Please confirm TAP / Device busy / same-ID resume are still safe without the wait @lisongqian cc |
fb8a84a to
829f025
Compare
The teardown thread wrote exit_evt once vm.shutdown() completed, which shut the vmm thread down from inside an API handler. Nothing on the pause exit path joins the vmm thread, so the write bought no ordering guarantee -- it only killed the API request server thread early. Drop the write and correct the comment: the vmm thread serves ApiRequests and its lifecycle belongs to the caller, exactly as before the async teardown change. Address review feedback on TencentCloud#1731.
…d before bind The device shutdown op's remove_file runs from DeviceManager::drop at the tail end of the now-asynchronous pause teardown, or never runs if the previous shim crashed -- either way the stale file can still occupy the path when the next shim for the same sandbox binds. Address review feedback on TencentCloud#1731.
AI-generated review
Scope reviewed: What the change does
VerdictNo blocking correctness defect found in the diff. The core mechanism is sound: the deferral can only make teardown later than before, never earlier, so it cannot introduce an early unmap or a use-after-free. I verified the load-bearing assumptions against the base tree:
The findings below are about semantics documentation, failure observability and drift risk — see the four inline comments. Findings
Testing / process notes
|
The teardown thread wrote exit_evt once vm.shutdown() completed, which shut the vmm thread down from inside an API handler. Nothing on the pause exit path joins the vmm thread, so the write bought no ordering guarantee -- it only killed the API request server thread early. Drop the write and correct the comment: the vmm thread serves ApiRequests and its lifecycle belongs to the caller, exactly as before the async teardown change. Address review feedback on TencentCloud#1731. Signed-off-by: lzh <740203701@qq.com>
20578d7 to
9b20dd8
Compare
|
@Eulogizethesun Thanks for your contribution. Please resolve the CI failure issue AND click "Resolve conversation" to ensure that all comments from cubesandboxbot are either approved or rejected. |
Clearing vm_config and moving the Vm to the teardown thread satisfies the VMM's "is there a VM?" predicate while the old Vm still holds its resources -- a VmCreate/VmBoot/VmRestore landing in that window would run concurrently with the destruction. Nothing sends these requests to a paused shim today (Cubelet reaps it right after the pause reply), so this is not reachable, but the invariant was implicit. Park the teardown handle in a dedicated field instead of self.threads: the three VM-creating entry points wait on it before their checks, so a request landing in the window sees exactly the state it would have seen against a synchronously deleted VM, and Vmm::drop joins the teardown on every exit path -- including the control_loop error returns that skip the thread drain. Address review feedback on TencentCloud#1731 (finding 1 and the join-guarantee part of finding 3). Signed-off-by: lzh <740203701@qq.com>
Extract Vmm::destroy_vm (counters logging + vm.shutdown()) so the
synchronous vm_shutdown path and the background pause teardown cannot
drift -- the closure previously skipped the counters-failure log. Emit
event!("vm", "deleted") from the teardown thread only after
vm.shutdown() completes, so the event keeps the meaning it has on the
synchronous vm_delete path instead of firing while the VM and its fds
are still alive.
Address review feedback on TencentCloud#1731 (findings 2 and 4).
Signed-off-by: lzh <740203701@qq.com>
… wiring Two follow-ups on the socket handover guard: log a warning when the muxer cannot record its socket identity at bind time (the shutdown op silently degrades to never unlinking, which would leave the file behind for the next bind), and spell out the check-vs-unlink TOCTOU window in the shutdown op comment instead of implying an atomic guarantee. Add a wiring test that drives Vsock::shutdown() through a real muxer backend: an own socket file must be unlinked, a successor's file bound at the same path must survive -- so the guard cannot be dropped from shutdown() with the helper-only test still green. Address review feedback on TencentCloud#1731 (findings 6 and 7). Signed-off-by: lzh <740203701@qq.com>
4acc296 to
d06e41b
Compare
|
@Eulogizethesun You don't have to resolve every issue in the AI report; you just need to make sure there are no issues of moderate severity or higher in the critical patch and make sure tests are covered. |
d06e41b to
48de5d0
Compare
48de5d0 to
aaa32f9
Compare
|
@lkml-likexu @lisongqian @ls-ggg The code is ready. Only the guest RAM unmap and the KVM fd close are deferred to a background thread; tap, vsock and the rest of the teardown are unchanged and still finish before the reply, so the TAP race mentioned earlier does not exist. All review feedback has been addressed, and CI is green. Could you take a look when you have a chance? |
|
Thank you for your efforts in improving performance. Can you update the performance data based on the latest code? @Eulogizethesun |
|
@lisongqian Updated. The data in the description is now measured with this change on top of v0.7.2: pause c1 149.8 → 88.4 ms (-41%), c50 515.9 → 411.8 ms (-20%). Is the code OK to merge? |
lisongqian
left a comment
There was a problem hiding this comment.
LGTM. Just a code style question; it doesn't block the PR.
…he pause reply The pause teardown runs the whole baseline destruction chain synchronously before replying: Vm::shutdown() wakes the parked workers, dropping the Vm kills them (each device Drop) and releases every host file -- the same chain vm_delete runs, so the reply still means the old VM is completely torn down. Only the two expensive tail steps are deferred: one reference of the memory manager -- which owns both the guest RAM and the hypervisor VM handle -- is held past the drop and released on a background thread, moving the unmap and the KVM fd close off the reply path. Signed-off-by: lzh <740203701@qq.com>
aaa32f9 to
3350a09
Compare





This PR optimizes pause performance.
Summary
Pausing a sandbox ends with tearing the paused VM down. That teardown used to run entirely before the pause reply: for a 2 GiB sandbox, the guest memory unmap and the KVM fd close alone cost about 60 ms.
This PR defers exactly those two steps. The reply still waits for the whole baseline teardown chain, the same one the delete path runs: Vm::shutdown() wakes the parked workers, and dropping the Vm kills them (each device's Drop writes its kill event), removes the vsock and vhost-user socket files, and closes the tap and disk fds and the queue eventfds. One reference of the memory manager -- which owns both the guest RAM and the hypervisor VM handle -- is held past that drop and released on a background thread, so the unmap and the KVM fd close happen after the reply. The unmap still cannot overtake anyone: it happens when the last reference goes, so a worker still exiting keeps the mapping alive until it is done.
What the reply means: vcpus joined, every worker killed, the vsock and vhost-user socket files removed, the tap and disk fds and the queue eventfds closed. Worker thread exits are asynchronous (the codebase joins only the net workers), so a thread may still be completing its exit at the reply.
Performance
Measured on v0.7.2 (2 GiB sandbox, pause to snapshot), before/after this change:
Resume latency is unchanged.
Testing