vm-device: support batch update interrupt source group GSI

Split interrupt source group restore into two steps, first restore
the irqfd for each interrupt source entry, and second restore the
GSI routing of the entire interrupt source group.

This patch will reduce restore latency of interrupt source group,
and in a 200-concurrent restore test, the patch reduced the
average IOAPIC restore time from 15ms to 1ms.

Signed-off-by: Yong He <alexyonghe@tencent.com>
This commit is contained in:
Yong He 2023-08-01 14:41:23 +08:00 committed by Rob Bradford
parent ecf3db5092
commit 0149e65081
11 changed files with 66 additions and 4 deletions

View File

@ -98,9 +98,14 @@ impl Gic {
i as InterruptIndex,
InterruptSourceConfig::LegacyIrq(config),
false,
false,
)
.map_err(Error::EnableInterrupt)?;
}
self.interrupt_source_group
.set_gsi()
.map_err(Error::EnableInterrupt)?;
Ok(())
}

View File

@ -237,9 +237,14 @@ impl Ioapic {
if state.is_some() {
for (irq, entry) in ioapic.used_entries.iter().enumerate() {
if *entry {
ioapic.update_entry(irq)?;
ioapic.update_entry(irq, false)?;
}
}
ioapic
.interrupt_source_group
.set_gsi()
.map_err(Error::UpdateInterrupt)?;
}
Ok(ioapic)
@ -278,7 +283,7 @@ impl Ioapic {
}
// The entry must be updated through the interrupt source
// group.
if let Err(e) = self.update_entry(index) {
if let Err(e) = self.update_entry(index, true) {
error!("Failed updating IOAPIC entry: {:?}", e);
}
// Store the information this IRQ is now being used.
@ -329,7 +334,7 @@ impl Ioapic {
}
}
fn update_entry(&self, irq: usize) -> Result<()> {
fn update_entry(&self, irq: usize, set_gsi: bool) -> Result<()> {
let entry = self.reg_entries[irq];
// Validate Destination Mode value, and retrieve Destination ID
@ -386,6 +391,7 @@ impl Ioapic {
irq as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
interrupt_mask(entry) == 1,
set_gsi,
)
.map_err(Error::UpdateInterrupt)?;

View File

@ -361,10 +361,15 @@ mod tests {
_index: InterruptIndex,
_config: InterruptSourceConfig,
_masked: bool,
_set_gsi: bool,
) -> result::Result<(), std::io::Error> {
Ok(())
}
fn set_gsi(&self) -> result::Result<(), std::io::Error> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
Some(self.event_fd.try_clone().unwrap())
}

View File

@ -413,10 +413,15 @@ mod tests {
_index: InterruptIndex,
_config: InterruptSourceConfig,
_masked: bool,
_set_gsi: bool,
) -> result::Result<(), std::io::Error> {
Ok(())
}
fn set_gsi(&self) -> result::Result<(), std::io::Error> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
Some(self.event_fd.try_clone().unwrap())
}

View File

@ -365,9 +365,13 @@ mod tests {
_index: InterruptIndex,
_config: InterruptSourceConfig,
_masked: bool,
_set_gsi: bool,
) -> result::Result<(), std::io::Error> {
Ok(())
}
fn set_gsi(&self) -> result::Result<(), std::io::Error> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
Some(self.event_fd.try_clone().unwrap())
}

View File

@ -485,9 +485,13 @@ mod tests {
_index: InterruptIndex,
_config: InterruptSourceConfig,
_masked: bool,
_set_gsi: bool,
) -> result::Result<(), std::io::Error> {
Ok(())
}
fn set_gsi(&self) -> result::Result<(), std::io::Error> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
Some(self.event_fd.try_clone().unwrap())
}

View File

@ -59,9 +59,13 @@ impl InterruptSourceGroup for TestInterrupt {
_index: InterruptIndex,
_config: InterruptSourceConfig,
_masked: bool,
_set_gsi: bool,
) -> Result<(), std::io::Error> {
Ok(())
}
fn set_gsi(&self) -> Result<(), std::io::Error> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
Some(self.event_fd.try_clone().unwrap())
}

View File

@ -205,10 +205,15 @@ impl MsiConfig {
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
state.cap.vector_masked(idx),
false,
)
.map_err(Error::UpdateInterruptRoute)?;
}
interrupt_source_group
.set_gsi()
.map_err(Error::EnableInterruptRoute)?;
interrupt_source_group
.enable()
.map_err(Error::EnableInterruptRoute)?;
@ -262,6 +267,7 @@ impl MsiConfig {
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
self.cap.vector_masked(idx),
true,
) {
error!("Failed updating vector: {:?}", e);
}

View File

@ -107,6 +107,7 @@ impl MsixConfig {
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
state.masked,
true,
)
.map_err(Error::UpdateInterruptRoute)?;
@ -182,6 +183,7 @@ impl MsixConfig {
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
table_entry.masked(),
true,
) {
error!("Failed updating vector: {:?}", e);
}
@ -320,6 +322,7 @@ impl MsixConfig {
index as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
table_entry.masked(),
true,
) {
error!("Failed updating vector: {:?}", e);
}

View File

@ -147,10 +147,15 @@ pub trait InterruptSourceGroup: Send + Sync {
/// * index: sub-index into the group.
/// * config: configuration data for the interrupt source.
/// * masked: if the interrupt is masked
/// * set_gsi: whehter update the GSI routing table.
fn update(
&self,
index: InterruptIndex,
config: InterruptSourceConfig,
masked: bool,
set_gsi: bool,
) -> Result<()>;
/// Set the interrupt group GSI routing table.
fn set_gsi(&self) -> Result<()>;
}

View File

@ -170,6 +170,7 @@ impl InterruptSourceGroup for MsiInterruptGroup {
index: InterruptIndex,
config: InterruptSourceConfig,
masked: bool,
set_gsi: bool,
) -> Result<()> {
if let Some(route) = self.irq_routes.get(&index) {
let entry = RoutingEntry {
@ -183,7 +184,11 @@ impl InterruptSourceGroup for MsiInterruptGroup {
}
let mut routes = self.gsi_msi_routes.lock().unwrap();
routes.insert(route.gsi, entry);
return self.set_gsi_routes(&routes);
if set_gsi {
return self.set_gsi_routes(&routes);
} else {
return Ok(());
}
}
Err(io::Error::new(
@ -191,6 +196,11 @@ impl InterruptSourceGroup for MsiInterruptGroup {
format!("update: Invalid interrupt index {index}"),
))
}
fn set_gsi(&self) -> Result<()> {
let routes = self.gsi_msi_routes.lock().unwrap();
self.set_gsi_routes(&routes)
}
}
pub struct LegacyUserspaceInterruptGroup {
@ -223,10 +233,15 @@ impl InterruptSourceGroup for LegacyUserspaceInterruptGroup {
_index: InterruptIndex,
_config: InterruptSourceConfig,
_masked: bool,
_set_gsi: bool,
) -> Result<()> {
Ok(())
}
fn set_gsi(&self) -> Result<()> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
self.ioapic.lock().unwrap().notifier(self.irq as usize)
}