diff options
author | Zide Chen <zide.chen@intel.corp-partner.google.com> | 2019-10-15 13:49:40 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-10-22 21:09:33 +0000 |
commit | aef6e53ed943ce3540d7aa189ce7da4b5877e167 (patch) | |
tree | 396e0d4e6f0fa9fb114206235fefdc353c3eaa36 | |
parent | 95dbad3db64a6bf16bc08985d660f8e7436cc478 (diff) | |
download | crosvm-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.rs | 26 |
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(()) |