mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: Add fast path for PCI config IO port
Looking up devices on the port I/O bus is time consuming during the
boot at there is an O(lg n) tree lookup and the overhead from taking a
lock on the bus contents.
Avoid this by adding a fast path uses the hardcoded port address and
size and directs PCI config requests directly to the device.
Command line:
target/release/cloud-hypervisor --kernel ~/src/linux/vmlinux --cmdline "root=/dev/vda1 console=ttyS0" --serial tty --console off --disk path=~/workloads/focal-server-cloudimg-amd64-custom-20210609-0.raw --api-socket /tmp/api
PIO exit: 17913
PCI fast path: 17871
Percentage on fast path: 99.8%
perf before:
marvin:~/src/cloud-hypervisor (main *)$ perf report -g | grep resolve
6.20% 6.20% vcpu0 cloud-hypervisor [.] vm_device::bus::Bus::resolve
perf after:
marvin:~/src/cloud-hypervisor (2021-09-17-ioapic-fast-path *)$ perf report -g | grep resolve
0.08% 0.08% vcpu0 cloud-hypervisor [.] vm_device::bus::Bus::resolve
The compromise required to implement this fast path is bringing the
creation of the PciConfigIo device into the DeviceManager::new() so that
it can be used in the VmmOps struct which is created before
DeviceManager::create_devices() is called.
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
@@ -65,6 +65,8 @@ use std::panic::AssertUnwindSafe;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::{result, str, thread};
|
||||
use vm_device::Bus;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use vm_device::BusDevice;
|
||||
use vm_memory::{
|
||||
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||
GuestMemoryRegion,
|
||||
@@ -360,6 +362,8 @@ struct VmOps {
|
||||
mmio_bus: Arc<Bus>,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
timestamp: std::time::Instant,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pci_config_io: Arc<Mutex<dyn BusDevice>>,
|
||||
}
|
||||
|
||||
impl VmOps {
|
||||
@@ -417,6 +421,17 @@ impl VmmOps for VmOps {
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn pio_read(&self, port: u64, data: &mut [u8]) -> hypervisor::vm::Result<()> {
|
||||
use pci::{PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
|
||||
|
||||
if (PCI_CONFIG_IO_PORT..(PCI_CONFIG_IO_PORT + PCI_CONFIG_IO_PORT_SIZE)).contains(&port) {
|
||||
self.pci_config_io.lock().unwrap().read(
|
||||
PCI_CONFIG_IO_PORT,
|
||||
port - PCI_CONFIG_IO_PORT,
|
||||
data,
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Err(vm_device::BusError::MissingAddressRange) = self.io_bus.read(port, data) {
|
||||
warn!("Guest PIO read to unregistered address 0x{:x}", port);
|
||||
}
|
||||
@@ -425,11 +440,22 @@ impl VmmOps for VmOps {
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn pio_write(&self, port: u64, data: &[u8]) -> hypervisor::vm::Result<()> {
|
||||
use pci::{PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
|
||||
|
||||
if port == DEBUG_IOPORT as u64 && data.len() == 1 {
|
||||
self.log_debug_ioport(data[0]);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if (PCI_CONFIG_IO_PORT..(PCI_CONFIG_IO_PORT + PCI_CONFIG_IO_PORT_SIZE)).contains(&port) {
|
||||
self.pci_config_io.lock().unwrap().write(
|
||||
PCI_CONFIG_IO_PORT,
|
||||
port - PCI_CONFIG_IO_PORT,
|
||||
data,
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match self.io_bus.write(port, data) {
|
||||
Err(vm_device::BusError::MissingAddressRange) => {
|
||||
warn!("Guest PIO write to unregistered address 0x{:x}", port);
|
||||
@@ -546,6 +572,10 @@ impl Vm {
|
||||
let mmio_bus = Arc::clone(device_manager.lock().unwrap().mmio_bus());
|
||||
// Create the VmOps structure, which implements the VmmOps trait.
|
||||
// And send it to the hypervisor.
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let pci_config_io =
|
||||
device_manager.lock().unwrap().pci_config_io() as Arc<Mutex<dyn BusDevice>>;
|
||||
let vm_ops: Arc<dyn VmmOps> = Arc::new(VmOps {
|
||||
memory,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@@ -553,6 +583,8 @@ impl Vm {
|
||||
mmio_bus,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
timestamp: std::time::Instant::now(),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pci_config_io,
|
||||
});
|
||||
|
||||
let exit_evt_clone = exit_evt.try_clone().map_err(Error::EventFdClone)?;
|
||||
|
||||
Reference in New Issue
Block a user