Skip to content

Commit 6421ea7

Browse files
committed
Use BootTimer to measure hotplug latency
Change the boot timer timestamp to be public, so that the timer can also be used for measuring hotplugging Signed-off-by: James Curtis <[email protected]>
1 parent e3893d3 commit 6421ea7

File tree

2 files changed

+87
-1
lines changed

2 files changed

+87
-1
lines changed

src/vmm/src/devices/pseudo/boot_timer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const MAGIC_VALUE_SIGNAL_GUEST_BOOT_COMPLETE: u8 = 123;
1010
/// Pseudo device to record the kernel boot time.
1111
#[derive(Debug)]
1212
pub struct BootTimer {
13-
start_ts: TimestampUs,
13+
pub start_ts: TimestampUs,
1414
}
1515

1616
impl BootTimer {

src/vmm/src/lib.rs

+86
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,92 @@ impl Vmm {
600600
Ok(cpu_configs)
601601
}
602602

603+
/// Adds new vCPUs to VMM.
604+
#[cfg(target_arch = "x86_64")]
605+
pub fn hotplug_vcpus(
606+
&mut self,
607+
config: HotplugVcpuConfig,
608+
) -> Result<MachineConfigUpdate, HotplugVcpuError> {
609+
use crate::logger::IncMetric;
610+
if config.add < 1 {
611+
return Err(HotplugVcpuError::VcpuCountTooLow);
612+
} else if self
613+
.vcpus_handles
614+
.len()
615+
.checked_add(config.add.into())
616+
.ok_or(HotplugVcpuError::VcpuCountTooHigh)?
617+
> MAX_SUPPORTED_VCPUS.into()
618+
{
619+
return Err(HotplugVcpuError::VcpuCountTooHigh);
620+
}
621+
622+
if let Some(kvm_config) = self.vcpu_config.as_mut() {
623+
kvm_config.vcpu_count += config.add;
624+
}
625+
// Create and start new vcpus
626+
let mut vcpus = Vec::with_capacity(config.add.into());
627+
628+
#[allow(clippy::cast_possible_truncation)]
629+
let start_idx = self.vcpus_handles.len().try_into().unwrap();
630+
if let Some(devices::BusDevice::CpuContainer(cont)) =
631+
self.get_bus_device(DeviceType::CpuContainer, "CpuContainer")
632+
{
633+
let mut locked_container = cont.lock().expect("Poisoned lock");
634+
for cpu_idx in start_idx..(start_idx + config.add) {
635+
let exit_evt = self
636+
.vcpus_exit_evt
637+
.try_clone()
638+
.map_err(HotplugVcpuError::EventFd)?;
639+
let mut vcpu =
640+
Vcpu::new(cpu_idx, &self.vm, exit_evt).map_err(HotplugVcpuError::VcpuCreate)?;
641+
if let Some(kvm_config) = self.vcpu_config.as_ref() {
642+
vcpu.kvm_vcpu.hotplug_configure(kvm_config)?;
643+
} else {
644+
return Err(HotplugVcpuError::RestoredFromSnapshot);
645+
}
646+
locked_container.cpu_devices[cpu_idx as usize].inserting = true;
647+
vcpus.push(vcpu);
648+
}
649+
}
650+
651+
self.start_vcpus(
652+
vcpus,
653+
self.seccomp_filters
654+
.get("vcpu")
655+
.ok_or_else(|| HotplugVcpuError::MissingSeccompFilters("vcpu".to_string()))?
656+
.clone(),
657+
)
658+
.map_err(HotplugVcpuError::VcpuStart)?;
659+
660+
#[allow(clippy::cast_lossless)]
661+
METRICS.hotplug.vcpus_added.add(config.add.into());
662+
663+
// Update VM config to reflect new CPUs added
664+
#[allow(clippy::cast_possible_truncation)]
665+
let new_machine_config = MachineConfigUpdate {
666+
vcpu_count: Some(self.vcpus_handles.len() as u8),
667+
mem_size_mib: None,
668+
smt: None,
669+
cpu_template: None,
670+
track_dirty_pages: None,
671+
huge_pages: None,
672+
};
673+
674+
self.resume_vcpu_threads(start_idx.into())?;
675+
676+
self.acpi_device_manager.notify_cpu_container()?;
677+
678+
#[cfg(test)]
679+
if let Some(devices::BusDevice::BootTimer(timer)) =
680+
self.get_bus_device(DeviceType::BootTimer, "BootTimer")
681+
{
682+
let mut locked_timer = timer.lock().expect("Poisoned lock");
683+
locked_timer.start_ts = utils::time::TimestampUs::default();
684+
}
685+
686+
Ok(new_machine_config)
687+
}
688+
603689
/// Retrieves the KVM dirty bitmap for each of the guest's memory regions.
604690
pub fn reset_dirty_bitmap(&self) {
605691
self.guest_memory

0 commit comments

Comments
 (0)