summary refs log tree commit diff
path: root/devices/src/virtio/vhost/worker.rs
diff options
context:
space:
mode:
authorXiong Zhang <xiong.y.zhang@intel.corp-partner.google.com>2019-09-05 19:29:30 +0800
committerCommit Bot <commit-bot@chromium.org>2019-10-25 23:59:43 +0000
commit3185ae95dd58f556a836f9e146dfe7b8450749b2 (patch)
treeb3eb1b569650d2a9fda7d864c622a5510e7d6b2a /devices/src/virtio/vhost/worker.rs
parent3530f2a2bb05f8ccf45d2fa452c9f9f4de547876 (diff)
downloadcrosvm-3185ae95dd58f556a836f9e146dfe7b8450749b2.tar
crosvm-3185ae95dd58f556a836f9e146dfe7b8450749b2.tar.gz
crosvm-3185ae95dd58f556a836f9e146dfe7b8450749b2.tar.bz2
crosvm-3185ae95dd58f556a836f9e146dfe7b8450749b2.tar.lz
crosvm-3185ae95dd58f556a836f9e146dfe7b8450749b2.tar.xz
crosvm-3185ae95dd58f556a836f9e146dfe7b8450749b2.tar.zst
crosvm-3185ae95dd58f556a836f9e146dfe7b8450749b2.zip
devices: enable MSI-X for virtio-net and viotio-block devices
- signal_used_queue(): trigger MSI-X interrupts to the guest if MSI-X is
  enabled, otherwise trigger INTx interrupts
- enable MSI-X on vhost-net: allocate one vhost_interrupt for every
  MSI-X vector.

Performance wise, fio random R/W test on eve pixelbook:

           INTx          MSI-X      delta
fio write  8.13MiB/s    9.79MiB/s   +1.66MiB/s (+20%)
fio read   24.35MiB/s   29.3MiB/s   +4.95MiB/s (+20%)

For networking performance (TCP stream), test results on eve pixelbook:

             INTx            MSI-X          delta
iperf3       5.93Gbits/s     6.57Gbits/s    +0.64Gbits/s (+10.7%)
iperf3 -R    5.68Gbits/s     7.37Gbits/s    +1.30Gbits/s (+22.8%)

iperf test results on VM launched from Ubuntu host (client sends only):

             INTx            MSI-X          delta
virtio-net   9.53Gbits/s     11.4 Gbits/s   +1.87Gbits/s (+19.5%)
vhost        28.34Gbits/s    44.43Gbits/s   +16.09Gbits/s (+56.7%)

BUG=chromium:854765
TEST=cargo test -p devices
TEST=tested virtio-net and block on Linux VM and eve pixelbook

Change-Id: Ic4952a094327e6b977f446def8209ea2f796878c
Signed-off-by: Xiong Zhang <xiong.y.zhang@intel.corp-partner.google.com>
Signed-off-by: Zide Chen <zide.chen@intel.corp-partner.google.com>
Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1828340
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'devices/src/virtio/vhost/worker.rs')
-rw-r--r--devices/src/virtio/vhost/worker.rs42
1 files changed, 29 insertions, 13 deletions
diff --git a/devices/src/virtio/vhost/worker.rs b/devices/src/virtio/vhost/worker.rs
index 54cbb63..26c1449 100644
--- a/devices/src/virtio/vhost/worker.rs
+++ b/devices/src/virtio/vhost/worker.rs
@@ -5,11 +5,13 @@
 use std::os::raw::c_ulonglong;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::Arc;
+use sync::Mutex;
 
 use sys_util::{EventFd, PollContext, PollToken};
 use vhost::Vhost;
 
 use super::{Error, Result};
+use crate::pci::MsixConfig;
 use crate::virtio::{Queue, INTERRUPT_STATUS_USED_RING};
 
 /// Worker that takes care of running the vhost device.  This mainly involves forwarding interrupts
@@ -19,10 +21,11 @@ use crate::virtio::{Queue, INTERRUPT_STATUS_USED_RING};
 pub struct Worker<T: Vhost> {
     queues: Vec<Queue>,
     vhost_handle: T,
-    vhost_interrupt: EventFd,
+    vhost_interrupt: Vec<EventFd>,
     interrupt_status: Arc<AtomicUsize>,
     interrupt_evt: EventFd,
     interrupt_resample_evt: EventFd,
+    msix_config: Option<Arc<Mutex<MsixConfig>>>,
     acked_features: u64,
 }
 
@@ -30,10 +33,11 @@ impl<T: Vhost> Worker<T> {
     pub fn new(
         queues: Vec<Queue>,
         vhost_handle: T,
-        vhost_interrupt: EventFd,
+        vhost_interrupt: Vec<EventFd>,
         interrupt_status: Arc<AtomicUsize>,
         interrupt_evt: EventFd,
         interrupt_resample_evt: EventFd,
+        msix_config: Option<Arc<Mutex<MsixConfig>>>,
         acked_features: u64,
     ) -> Worker<T> {
         Worker {
@@ -43,11 +47,20 @@ impl<T: Vhost> Worker<T> {
             interrupt_status,
             interrupt_evt,
             interrupt_resample_evt,
+            msix_config,
             acked_features,
         }
     }
 
-    fn signal_used_queue(&self) {
+    fn signal_used_queue(&self, vector: u16) {
+        if let Some(msix_config) = &self.msix_config {
+            let mut msix_config = msix_config.lock();
+            if msix_config.enabled() {
+                msix_config.trigger(vector);
+                return;
+            }
+        }
+
         self.interrupt_status
             .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
         self.interrupt_evt.write(1).unwrap();
@@ -103,7 +116,7 @@ impl<T: Vhost> Worker<T> {
                 .set_vring_base(queue_index, 0)
                 .map_err(Error::VhostSetVringBase)?;
             self.vhost_handle
-                .set_vring_call(queue_index, &self.vhost_interrupt)
+                .set_vring_call(queue_index, &self.vhost_interrupt[queue_index])
                 .map_err(Error::VhostSetVringCall)?;
             self.vhost_handle
                 .set_vring_kick(queue_index, &queue_evts[queue_index])
@@ -114,27 +127,33 @@ impl<T: Vhost> Worker<T> {
 
         #[derive(PollToken)]
         enum Token {
-            VhostIrq,
+            VhostIrqi { index: usize },
             InterruptResample,
             Kill,
         }
 
         let poll_ctx: PollContext<Token> = PollContext::build_with(&[
-            (&self.vhost_interrupt, Token::VhostIrq),
             (&self.interrupt_resample_evt, Token::InterruptResample),
             (&kill_evt, Token::Kill),
         ])
         .map_err(Error::CreatePollContext)?;
 
+        for (index, vhost_int) in self.vhost_interrupt.iter().enumerate() {
+            poll_ctx
+                .add(vhost_int, Token::VhostIrqi { index })
+                .map_err(Error::CreatePollContext)?;
+        }
+
         'poll: loop {
             let events = poll_ctx.wait().map_err(Error::PollError)?;
 
-            let mut needs_interrupt = false;
             for event in events.iter_readable() {
                 match event.token() {
-                    Token::VhostIrq => {
-                        needs_interrupt = true;
-                        self.vhost_interrupt.read().map_err(Error::VhostIrqRead)?;
+                    Token::VhostIrqi { index } => {
+                        self.vhost_interrupt[index]
+                            .read()
+                            .map_err(Error::VhostIrqRead)?;
+                        self.signal_used_queue(self.queues[index].vector);
                     }
                     Token::InterruptResample => {
                         let _ = self.interrupt_resample_evt.read();
@@ -145,9 +164,6 @@ impl<T: Vhost> Worker<T> {
                     Token::Kill => break 'poll,
                 }
             }
-            if needs_interrupt {
-                self.signal_used_queue();
-            }
         }
         Ok(())
     }