guest->host throughput with 01-tx-notifies-disabled-for-longer

guest->host host->guest || cpu utilization throughput vmexits || 01-tx-notifies-disabled-for-longer 02-flush-in-io-thread 03-catch-more-io 04-no-tx-timer 05-drop-mutex

From: Mark McLoughlin 
Subject: [PATCH] kvm: qemu: virtio_net: keep tx notifies disabled for longer

Keep tx notifies disabled while we flush the queue and then
re-check the queue once we have re-enabled notifies.

This should reduce the number of vmexits with any significant
packet rate.

Signed-off-by: Mark McLoughlin 
---
 qemu/hw/virtio-net.c |   13 ++++++++-----
 1 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/qemu/hw/virtio-net.c b/qemu/hw/virtio-net.c
index 6460c9f..e816041 100644
--- a/qemu/hw/virtio-net.c
+++ b/qemu/hw/virtio-net.c
@@ -227,7 +227,7 @@ static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
 }
 
 /* TX */
-static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
+static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq, int enable_notify)
 {
     VirtQueueElement elem;
     int has_vnet_hdr = tap_has_vnet_hdr(n->vc->vlan->first_client);
@@ -257,6 +257,11 @@ static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
 	virtqueue_push(vq, &elem, len);
 	virtio_notify(&n->vdev, vq);
     }
+
+    if (enable_notify) {
+	vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
+	virtio_net_flush_tx(n, vq, 0);
+    }
 }
 
 static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
@@ -264,10 +269,9 @@ static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
     VirtIONet *n = to_virtio_net(vdev);
 
     if (n->tx_timer_active) {
-	vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
 	qemu_del_timer(n->tx_timer);
 	n->tx_timer_active = 0;
-	virtio_net_flush_tx(n, vq);
+	virtio_net_flush_tx(n, n->tx_vq, 1);
     } else {
 	qemu_mod_timer(n->tx_timer,
 		       qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
@@ -282,8 +286,7 @@ static void virtio_net_tx_timer(void *opaque)
 
     n->tx_timer_active = 0;
 
-    n->tx_vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
-    virtio_net_flush_tx(n, n->tx_vq);
+    virtio_net_flush_tx(n, n->tx_vq, 1);
 }
 
 static void virtio_net_save(QEMUFile *f, void *opaque)
-- 
1.6.0.1

If you're interested, the nasty scripts I used to generate these are here