summary refs log tree commit diff
diff options
context:
space:
mode:
authorZide Chen <zide.chen@intel.corp-partner.google.com>2019-10-15 13:49:40 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-22 21:09:33 +0000
commitaef6e53ed943ce3540d7aa189ce7da4b5877e167 (patch)
tree396e0d4e6f0fa9fb114206235fefdc353c3eaa36
parent95dbad3db64a6bf16bc08985d660f8e7436cc478 (diff)
downloadcrosvm-aef6e53ed943ce3540d7aa189ce7da4b5877e167.tar
crosvm-aef6e53ed943ce3540d7aa189ce7da4b5877e167.tar.gz
crosvm-aef6e53ed943ce3540d7aa189ce7da4b5877e167.tar.bz2
crosvm-aef6e53ed943ce3540d7aa189ce7da4b5877e167.tar.lz
crosvm-aef6e53ed943ce3540d7aa189ce7da4b5877e167.tar.xz
crosvm-aef6e53ed943ce3540d7aa189ce7da4b5877e167.tar.zst
crosvm-aef6e53ed943ce3540d7aa189ce7da4b5877e167.zip
virtio-net: reduce number of virtual interrupts to the guest
It's quite costly to inject virtual interrupt to the guest, especially
in INTx case.

To reduce the number of interrupts, in process_rx(), we don't have to
inject interrupt on every frame, but wait until process_rx() finishes
processing all frames.

On eve, iperf3 gets ~15% improvement, "iperf3 -R" gets ~30% improvement.

BUG=chromium:854765
TEST=iperf3 on eve and Linux

Change-Id: Ie0560d8f42235d2371addb6de34c5f93d11a405f
Signed-off-by: Zide Chen <zide.chen@intel.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1865021
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Commit-Queue: Stephen Barber <smbarber@chromium.org>
Tested-by: Stephen Barber <smbarber@chromium.org>
-rw-r--r--devices/src/virtio/net.rs26
1 files changed, 20 insertions, 6 deletions
diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs
index 6bc2e25..3fb3ec1 100644
--- a/devices/src/virtio/net.rs
+++ b/devices/src/virtio/net.rs
@@ -145,14 +145,13 @@ where
 
         self.rx_queue.add_used(&self.mem, index, bytes_written);
 
-        // Interrupt the guest immediately for received frames to
-        // reduce latency.
-        self.signal_used_queue();
-
         true
     }
 
-    fn process_rx(&mut self) {
+    fn process_rx(&mut self) -> bool {
+        let mut needs_interrupt = false;
+        let mut first_frame = true;
+
         // Read as many frames as possible.
         loop {
             let res = self.tap.read(&mut self.rx_buf);
@@ -162,6 +161,11 @@ where
                     if !self.rx_single_frame() {
                         self.deferred_rx = true;
                         break;
+                    } else if first_frame {
+                        self.signal_used_queue();
+                        first_frame = false;
+                    } else {
+                        needs_interrupt = true;
                     }
                 }
                 Err(e) => {
@@ -174,6 +178,8 @@ where
                 }
             }
         }
+
+        needs_interrupt
     }
 
     fn process_tx(&mut self) {
@@ -251,6 +257,7 @@ where
         'poll: loop {
             let events = poll_ctx.wait().map_err(NetError::PollError)?;
             for event in events.iter_readable() {
+                let mut needs_interrupt_rx = false;
                 match event.token() {
                     Token::RxTap => {
                         // Process a deferred frame first if available. Don't read from tap again
@@ -258,6 +265,7 @@ where
                         if self.deferred_rx {
                             if self.rx_single_frame() {
                                 self.deferred_rx = false;
+                                needs_interrupt_rx = true;
                             } else {
                                 // There is an outstanding deferred frame and the guest has not yet
                                 // made any buffers available. Remove the tapfd from the poll
@@ -268,7 +276,7 @@ where
                                 continue;
                             }
                         }
-                        self.process_rx();
+                        needs_interrupt_rx |= self.process_rx();
                     }
                     Token::RxQueue => {
                         if let Err(e) = rx_queue_evt.read() {
@@ -277,6 +285,8 @@ where
                         }
                         // There should be a buffer available now to receive the frame into.
                         if self.deferred_rx && self.rx_single_frame() {
+                            needs_interrupt_rx = true;
+
                             // The guest has made buffers available, so add the tap back to the
                             // poll context in case it was removed.
                             match poll_ctx.add(&self.tap, Token::RxTap) {
@@ -304,6 +314,10 @@ where
                     }
                     Token::Kill => break 'poll,
                 }
+
+                if needs_interrupt_rx {
+                    self.signal_used_queue();
+                }
             }
         }
         Ok(())