mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: cpu_manager: massively accelerate .pause()
With 254 vCPUs, pausing now takes ~4ms instead of >254ms. This improvement is visible when running `ch-remote pause` and is particularly important for live migration, where every millisecond of downtime matters. For the wait logic, it is fine to stick to the approach of sleeping 1ms on the first missed ACK as: 1) we have to wait anyway 2) we give time to the OS, enabling it to schedule a vCPU thread next Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de> On-behalf-of: SAP philipp.schuster@sap.com
This commit is contained in:
committed by
Alyssa Ross
parent
34c5a081aa
commit
c1f4df600f
@@ -639,13 +639,25 @@ impl VcpuState {
|
||||
self.handle.is_some()
|
||||
}
|
||||
|
||||
/// Sends a signal to the underlying thread.
|
||||
///
|
||||
/// Please call [`Self::wait_until_signal_acknowledged`] afterward to block
|
||||
/// until the vCPU thread has acknowledged the signal.
|
||||
fn signal_thread(&self) {
|
||||
if let Some(handle) = self.handle.as_ref() {
|
||||
// SAFETY: FFI call with correct arguments
|
||||
unsafe {
|
||||
libc::pthread_kill(handle.as_pthread_t() as _, SIGRTMIN());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Blocks until the vCPU thread has acknowledged the signal.
|
||||
///
|
||||
/// This is the counterpart of [`Self::signal_thread`].
|
||||
fn wait_until_signal_acknowledged(&self) {
|
||||
if let Some(_handle) = self.handle.as_ref() {
|
||||
loop {
|
||||
// SAFETY: FFI call with correct arguments
|
||||
unsafe {
|
||||
libc::pthread_kill(handle.as_pthread_t() as _, SIGRTMIN());
|
||||
}
|
||||
if self.vcpu_run_interrupted.load(Ordering::SeqCst) {
|
||||
break;
|
||||
} else {
|
||||
@@ -1299,6 +1311,7 @@ impl CpuManager {
|
||||
let state = &mut self.vcpu_states[usize::try_from(cpu_id).unwrap()];
|
||||
state.kill.store(true, Ordering::SeqCst);
|
||||
state.signal_thread();
|
||||
state.wait_until_signal_acknowledged();
|
||||
state.join_thread()?;
|
||||
state.handle = None;
|
||||
|
||||
@@ -1366,6 +1379,21 @@ impl CpuManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Signal to the spawned threads (vCPUs and console signal handler).
|
||||
///
|
||||
/// For the vCPU threads this will interrupt the KVM_RUN ioctl() allowing
|
||||
/// the loop to check the shared state booleans.
|
||||
fn signal_vcpus(&self) {
|
||||
// Splitting this into two loops reduced the time to pause many vCPUs
|
||||
// massively. Example: 254 vCPUs. >254ms -> ~4ms.
|
||||
for state in self.vcpu_states.iter() {
|
||||
state.signal_thread();
|
||||
}
|
||||
for state in self.vcpu_states.iter() {
|
||||
state.wait_until_signal_acknowledged();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shutdown(&mut self) -> Result<()> {
|
||||
// Tell the vCPUs to stop themselves next time they go through the loop
|
||||
self.vcpus_kill_signalled.store(true, Ordering::SeqCst);
|
||||
@@ -1378,12 +1406,7 @@ impl CpuManager {
|
||||
state.unpark_thread();
|
||||
}
|
||||
|
||||
// Signal to the spawned threads (vCPUs and console signal handler). For the vCPU threads
|
||||
// this will interrupt the KVM_RUN ioctl() allowing the loop to check the boolean set
|
||||
// above.
|
||||
for state in self.vcpu_states.iter() {
|
||||
state.signal_thread();
|
||||
}
|
||||
self.signal_vcpus();
|
||||
|
||||
// Wait for all the threads to finish. This removes the state from the vector.
|
||||
for mut state in self.vcpu_states.drain(..) {
|
||||
@@ -1934,11 +1957,7 @@ impl CpuManager {
|
||||
|
||||
pub(crate) fn nmi(&self) -> Result<()> {
|
||||
self.vcpus_kick_signalled.store(true, Ordering::SeqCst);
|
||||
|
||||
for state in self.vcpu_states.iter() {
|
||||
state.signal_thread();
|
||||
}
|
||||
|
||||
self.signal_vcpus();
|
||||
self.vcpus_kick_signalled.store(false, Ordering::SeqCst);
|
||||
|
||||
Ok(())
|
||||
@@ -2300,12 +2319,7 @@ impl Pausable for CpuManager {
|
||||
// Tell the vCPUs to pause themselves next time they exit
|
||||
self.vcpus_pause_signalled.store(true, Ordering::SeqCst);
|
||||
|
||||
// Signal to the spawned threads (vCPUs and console signal handler). For the vCPU threads
|
||||
// this will interrupt the KVM_RUN ioctl() allowing the loop to check the boolean set
|
||||
// above.
|
||||
for state in self.vcpu_states.iter() {
|
||||
state.signal_thread();
|
||||
}
|
||||
self.signal_vcpus();
|
||||
|
||||
for vcpu in self.vcpus.iter() {
|
||||
let mut vcpu = vcpu.lock().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user