Skip to contentSkip to conversation

virtio: don't poll masked vectors with irqfd

PATCH In review Michael S. Tsirkin 3 participants 10 messages Dec 18, 2012 – Dec 19, 2012 KVM

lore
Share & tools
lore
#0 lore raw

cover virtio: don't poll masked vectors with irqfd

At the moment when vector is masked virtio will poll it in userspace, even if it is handled by irqfd.
This is done in order to update pending bits, but it's not really required until someone reads the pending bits. On the other hand this read results in extra io thread wakeups.

As we only implement the pending bits as a compatibility feature (read - real drivers don't use it), we can defer the irqfd poll until the read actually happens.

This does not seem to affect vhost-net speed
in simple benchmarks but could help block: both vhost-blk and dataplane when using irqfd,
and I also think this is cleaner than enabling/disabling notifiers all the time.

This will also be the basis for future optimizations.

Michael S. Tsirkin (3):
msi: add API to get notified about pending bit poll
msix: expose access to masked/pending state
virtio-pci: don't poll masked vectors

 hw/pci/msix.c   | 19 +++++++++++++++----
 hw/pci/msix.h   |  6 +++++-
 hw/pci/pci.h    |  4 ++++
 hw/vfio_pci.c   |  2 +-
 hw/virtio-pci.c | 53 +++++++++++++++++++++++++++++++++++++++++------------
 5 files changed, 66 insertions(+), 18 deletions(-)
Signature · 1 line
MST
#1 lore raw

PATCH 1/3 msi: add API to get notified about pending bit poll

Update all users.

---
 hw/pci/msix.c   | 13 ++++++++++++-
 hw/pci/msix.h   |  3 ++-
 hw/pci/pci.h    |  4 ++++
 hw/vfio_pci.c   |  2 +-
 hw/virtio-pci.c |  3 ++-
 5 files changed, 21 insertions(+), 4 deletions(-)
hw/pci/msix.c +12 -1
index 917327b..1f31975 100644
@@ -192,6 +192,11 @@ static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr,
                                    unsigned size)
 {
     PCIDevice *dev = opaque;
+    if (dev->msix_vector_poll_notifier) {
+        unsigned vector_start = addr * 8;
+        unsigned vector_end = MIN(addr + size * 8, dev->msix_entries_nr);
+        dev->msix_vector_poll_notifier(dev, vector_start, vector_end);
+    }
 
     return pci_get_long(dev->msix_pba + addr);
 }
@@ -515,7 +520,8 @@ static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector)
 
 int msix_set_vector_notifiers(PCIDevice *dev,
                               MSIVectorUseNotifier use_notifier,
-                              MSIVectorReleaseNotifier release_notifier)
+                              MSIVectorReleaseNotifier release_notifier,
+                              MSIVectorPollNotifier poll_notifier)
 {
     int vector, ret;
 
@@ -523,6 +529,7 @@ int msix_set_vector_notifiers(PCIDevice *dev,
 
     dev->msix_vector_use_notifier = use_notifier;
     dev->msix_vector_release_notifier = release_notifier;
+    dev->msix_vector_poll_notifier = poll_notifier;
 
     if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
         (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) {
@@ -533,6 +540,9 @@ int msix_set_vector_notifiers(PCIDevice *dev,
             }
         }
     }
+    if (dev->msix_vector_poll_notifier) {
+        dev->msix_vector_poll_notifier(dev, 0, dev->msix_entries_nr);
+    }
     return 0;
 
 undo:
@@ -559,4 +569,5 @@ void msix_unset_vector_notifiers(PCIDevice *dev)
     }
     dev->msix_vector_use_notifier = NULL;
     dev->msix_vector_release_notifier = NULL;
+    dev->msix_vector_poll_notifier = NULL;
 }
hw/pci/msix.h +2 -1
index ff07ae2..ea85d02 100644
@@ -36,6 +36,7 @@ void msix_reset(PCIDevice *dev);
 
 int msix_set_vector_notifiers(PCIDevice *dev,
                               MSIVectorUseNotifier use_notifier,
-                              MSIVectorReleaseNotifier release_notifier);
+                              MSIVectorReleaseNotifier release_notifier,
+                              MSIVectorPollNotifier poll_notifier);
 void msix_unset_vector_notifiers(PCIDevice *dev);
 #endif
hw/pci/pci.h +4 -0
index 41e5ddd..f80f8fb 100644
@@ -187,6 +187,9 @@ typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev);
 typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector,
                                       MSIMessage msg);
 typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector);
+typedef void (*MSIVectorPollNotifier)(PCIDevice *dev,
+                                      unsigned int vector_start,
+                                      unsigned int vector_end);
 
 struct PCIDevice {
     DeviceState qdev;
@@ -271,6 +274,7 @@ struct PCIDevice {
     /* MSI-X notifiers */
     MSIVectorUseNotifier msix_vector_use_notifier;
     MSIVectorReleaseNotifier msix_vector_release_notifier;
+    MSIVectorPollNotifier msix_vector_poll_notifier;
 };
 
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
hw/vfio_pci.c +1 -1
index 45d90ab..80c11de 100644
@@ -697,7 +697,7 @@ static void vfio_enable_msix(VFIODevice *vdev)
     vdev->interrupt = VFIO_INT_MSIX;
 
     if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use,
-                                  vfio_msix_vector_release)) {
+                                  vfio_msix_vector_release, NULL)) {
         error_report("vfio: msix_set_vector_notifiers failed\n");
     }
 
hw/virtio-pci.c +2 -1
index 518fb8a..1c03bb5 100644
@@ -638,7 +638,8 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign)
                       msix_nr_vectors_allocated(&proxy->pci_dev));
         r = msix_set_vector_notifiers(&proxy->pci_dev,
                                       kvm_virtio_pci_vector_use,
-                                      kvm_virtio_pci_vector_release);
+                                      kvm_virtio_pci_vector_release,
+                                      NULL);
         if (r < 0) {
             goto assign_error;
         }
Signature · 1 line
MST
#2 lore raw

PATCH 2/3 msix: expose access to masked/pending state

In reply to Michael S. Tsirkin

For use by poll handler.

---
 hw/pci/msix.c | 6 +++---
 hw/pci/msix.h | 3 +++
 2 files changed, 6 insertions(+), 3 deletions(-)
hw/pci/msix.c +3 -3
index 1f31975..9df0ffb 100644
@@ -65,7 +65,7 @@ static int msix_is_pending(PCIDevice *dev, int vector)
     return *msix_pending_byte(dev, vector) & msix_pending_mask(vector);
 }
 
-static void msix_set_pending(PCIDevice *dev, int vector)
+void msix_set_pending(PCIDevice *dev, unsigned int vector)
 {
     *msix_pending_byte(dev, vector) |= msix_pending_mask(vector);
 }
@@ -75,13 +75,13 @@ static void msix_clr_pending(PCIDevice *dev, int vector)
     *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector);
 }
 
-static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask)
+static bool msix_vector_masked(PCIDevice *dev, unsigned int vector, bool fmask)
 {
     unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
     return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
 }
 
-static bool msix_is_masked(PCIDevice *dev, int vector)
+bool msix_is_masked(PCIDevice *dev, unsigned int vector)
 {
     return msix_vector_masked(dev, vector, dev->msix_function_masked);
 }
hw/pci/msix.h +3 -0
index ea85d02..d0c4429 100644
@@ -26,6 +26,9 @@ void msix_load(PCIDevice *dev, QEMUFile *f);
 int msix_enabled(PCIDevice *dev);
 int msix_present(PCIDevice *dev);
 
+bool msix_is_masked(PCIDevice *dev, unsigned vector);
+void msix_set_pending(PCIDevice *dev, unsigned vector);
+
 int msix_vector_use(PCIDevice *dev, unsigned vector);
 void msix_vector_unuse(PCIDevice *dev, unsigned vector);
 void msix_unuse_all_vectors(PCIDevice *dev);
Signature · 1 line
MST
#3 lore raw

PATCH 3/3 virtio-pci: don't poll masked vectors

In reply to Michael S. Tsirkin

At the moment, when irqfd is in use but a vector is masked, qemu will poll it and handle vector masks in userspace. Since almost no one ever looks at the pending bits, it is better to defer this until pending bits
are actually read.
Implement this optimization using the new poll notifier.

---
 hw/virtio-pci.c | 52 ++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 40 insertions(+), 12 deletions(-)
hw/virtio-pci.c +40 -12
index 1c03bb5..bc6b4e0 100644
@@ -509,8 +509,6 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
         }
         return ret;
     }
-
-    virtio_queue_set_guest_notifier_fd_handler(vq, true, true);
     return 0;
 }
 
@@ -529,8 +527,6 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
     if (--irqfd->users == 0) {
         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
     }
-
-    virtio_queue_set_guest_notifier_fd_handler(vq, true, false);
 }
 
 static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector,
@@ -581,7 +577,36 @@ static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector)
     }
 }
 
-static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign)
+static void kvm_virtio_pci_vector_poll(PCIDevice *dev,
+                                       unsigned int vector_start,
+                                       unsigned int vector_end)
+{
+    VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
+    VirtIODevice *vdev = proxy->vdev;
+    int queue_no;
+    unsigned int vector;
+    EventNotifier *notifier;
+    VirtQueue *vq;
+
+    for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) {
+        if (!virtio_queue_get_num(vdev, queue_no)) {
+            break;
+        }
+        vector = virtio_queue_vector(vdev, queue_no);
+        if (vector < vector_start || vector >= vector_end ||
+            !msix_is_masked(dev, vector)) {
+            continue;
+        }
+        vq = virtio_get_queue(vdev, queue_no);
+        notifier = virtio_queue_get_guest_notifier(vq);
+        if (event_notifier_test_and_clear(notifier)) {
+            msix_set_pending(dev, vector);
+        }
+    }
+}
+
+static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
+                                         bool with_irqfd)
 {
     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
     VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
@@ -592,9 +617,9 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign)
         if (r < 0) {
             return r;
         }
-        virtio_queue_set_guest_notifier_fd_handler(vq, true, false);
+        virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
     } else {
-        virtio_queue_set_guest_notifier_fd_handler(vq, false, false);
+        virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
         event_notifier_cleanup(notifier);
     }
 
@@ -612,9 +637,11 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign)
     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
     VirtIODevice *vdev = proxy->vdev;
     int r, n;
+    bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
+        kvm_msi_via_irqfd_enabled();
 
     /* Must unset vector notifier while guest notifier is still assigned */
-    if (kvm_msi_via_irqfd_enabled() && !assign) {
+    if (with_irqfd && !assign) {
         msix_unset_vector_notifiers(&proxy->pci_dev);
         g_free(proxy->vector_irqfd);
         proxy->vector_irqfd = NULL;
@@ -625,21 +652,22 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign)
             break;
         }
 
-        r = virtio_pci_set_guest_notifier(d, n, assign);
+        r = virtio_pci_set_guest_notifier(d, n, assign,
+                                          kvm_msi_via_irqfd_enabled());
         if (r < 0) {
             goto assign_error;
         }
     }
 
     /* Must set vector notifier after guest notifier has been assigned */
-    if (kvm_msi_via_irqfd_enabled() && assign) {
+    if (with_irqfd && assign) {
         proxy->vector_irqfd =
             g_malloc0(sizeof(*proxy->vector_irqfd) *
                       msix_nr_vectors_allocated(&proxy->pci_dev));
         r = msix_set_vector_notifiers(&proxy->pci_dev,
                                       kvm_virtio_pci_vector_use,
                                       kvm_virtio_pci_vector_release,
-                                      NULL);
+                                      kvm_virtio_pci_vector_poll);
         if (r < 0) {
             goto assign_error;
         }
@@ -651,7 +679,7 @@ assign_error:
     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
     assert(assign);
     while (--n >= 0) {
-        virtio_pci_set_guest_notifier(d, n, !assign);
+        virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
     }
     return r;
 }
Signature · 1 line
MST
#4 lore raw

Re: [PATCH 3/3] virtio-pci: don't poll masked vectors

Quoted 73 lines · Michael S. Tsirkin

At the moment, when irqfd is in use but a vector is masked, qemu will poll it and handle vector masks in userspace. Since almost no one ever looks at the pending bits, it is better to defer this until pending bits
are actually read.
Implement this optimization using the new poll notifier.

---
 hw/virtio-pci.c | 52 ++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 40 insertions(+), 12 deletions(-)
hw/virtio-pci.c +30 -5
index 1c03bb5..bc6b4e0 100644
@@ -509,8 +509,6 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
         }
         return ret;
     }
-
-    virtio_queue_set_guest_notifier_fd_handler(vq, true, true);
     return 0;
 }
 
@@ -529,8 +527,6 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
     if (--irqfd->users == 0) {
         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
     }
-
-    virtio_queue_set_guest_notifier_fd_handler(vq, true, false);
 }
 
 static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector,
@@ -581,7 +577,36 @@ static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector)
     }
 }
 
-static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign)
+static void kvm_virtio_pci_vector_poll(PCIDevice *dev,
+                                       unsigned int vector_start,
+                                       unsigned int vector_end)
+{
+    VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
+    VirtIODevice *vdev = proxy->vdev;
+    int queue_no;
+    unsigned int vector;
+    EventNotifier *notifier;
+    VirtQueue *vq;
+
+    for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) {
+        if (!virtio_queue_get_num(vdev, queue_no)) {
+            break;
+        }
+        vector = virtio_queue_vector(vdev, queue_no);
+        if (vector < vector_start || vector >= vector_end ||
+            !msix_is_masked(dev, vector)) {
+            continue;
+        }
+        vq = virtio_get_queue(vdev, queue_no);
+        notifier = virtio_queue_get_guest_notifier(vq);
+        if (event_notifier_test_and_clear(notifier)) {
+            msix_set_pending(dev, vector);
+        }
+    }
+}
+
+static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
+                                         bool with_irqfd)
 {
     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
     VirtQueue *vq = virtio_get_queue(proxy->vdev, n);

hw/virtio-pci.c static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign) · line 620

Quoted 5 lines
hw/virtio-pci.c +1 -1
@@ -592,9 +617,9 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign)
         if (r < 0) {
             return r;
         }
-        virtio_queue_set_guest_notifier_fd_handler(vq, true, false);
+        virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);

+ virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd);

hw/virtio-pci.c static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign) · line 622

Quoted 3 lines
hw/virtio-pci.c +1 -1
     } else {
-        virtio_queue_set_guest_notifier_fd_handler(vq, false, false);
+        virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);

+ virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd);

Use the 'assign' variable instead of the constants?

Quoted 52 lines
hw/virtio-pci.c +8 -5
         event_notifier_cleanup(notifier);
     }
 
@@ -612,9 +637,11 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign)
     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
     VirtIODevice *vdev = proxy->vdev;
     int r, n;
+    bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
+        kvm_msi_via_irqfd_enabled();
 
     /* Must unset vector notifier while guest notifier is still assigned */
-    if (kvm_msi_via_irqfd_enabled() && !assign) {
+    if (with_irqfd && !assign) {
         msix_unset_vector_notifiers(&proxy->pci_dev);
         g_free(proxy->vector_irqfd);
         proxy->vector_irqfd = NULL;
@@ -625,21 +652,22 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign)
             break;
         }
 
-        r = virtio_pci_set_guest_notifier(d, n, assign);
+        r = virtio_pci_set_guest_notifier(d, n, assign,
+                                          kvm_msi_via_irqfd_enabled());
         if (r < 0) {
             goto assign_error;
         }
     }
 
     /* Must set vector notifier after guest notifier has been assigned */
-    if (kvm_msi_via_irqfd_enabled() && assign) {
+    if (with_irqfd && assign) {
         proxy->vector_irqfd =
             g_malloc0(sizeof(*proxy->vector_irqfd) *
                       msix_nr_vectors_allocated(&proxy->pci_dev));
         r = msix_set_vector_notifiers(&proxy->pci_dev,
                                       kvm_virtio_pci_vector_use,
                                       kvm_virtio_pci_vector_release,
-                                      NULL);
+                                      kvm_virtio_pci_vector_poll);
         if (r < 0) {
             goto assign_error;
         }
@@ -651,7 +679,7 @@ assign_error:
     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
     assert(assign);
     while (--n >= 0) {
-        virtio_pci_set_guest_notifier(d, n, !assign);
+        virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
     }
     return r;
 }
Signature · 1 line
Asias
#5 lore raw

Re: [PATCH 3/3] virtio-pci: don't poll masked vectors

Quoted 82 lines · Asias He
Quoted 73 lines · Michael S. Tsirkin

At the moment, when irqfd is in use but a vector is masked, qemu will poll it and handle vector masks in userspace. Since almost no one ever looks at the pending bits, it is better to defer this until pending bits
are actually read.
Implement this optimization using the new poll notifier.

---
 hw/virtio-pci.c | 52 ++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 40 insertions(+), 12 deletions(-)
hw/virtio-pci.c +30 -5
index 1c03bb5..bc6b4e0 100644
@@ -509,8 +509,6 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
         }
         return ret;
     }
-
-    virtio_queue_set_guest_notifier_fd_handler(vq, true, true);
     return 0;
 }
 
@@ -529,8 +527,6 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
     if (--irqfd->users == 0) {
         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
     }
-
-    virtio_queue_set_guest_notifier_fd_handler(vq, true, false);
 }
 
 static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector,
@@ -581,7 +577,36 @@ static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector)
     }
 }
 
-static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign)
+static void kvm_virtio_pci_vector_poll(PCIDevice *dev,
+                                       unsigned int vector_start,
+                                       unsigned int vector_end)
+{
+    VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
+    VirtIODevice *vdev = proxy->vdev;
+    int queue_no;
+    unsigned int vector;
+    EventNotifier *notifier;
+    VirtQueue *vq;
+
+    for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) {
+        if (!virtio_queue_get_num(vdev, queue_no)) {
+            break;
+        }
+        vector = virtio_queue_vector(vdev, queue_no);
+        if (vector < vector_start || vector >= vector_end ||
+            !msix_is_masked(dev, vector)) {
+            continue;
+        }
+        vq = virtio_get_queue(vdev, queue_no);
+        notifier = virtio_queue_get_guest_notifier(vq);
+        if (event_notifier_test_and_clear(notifier)) {
+            msix_set_pending(dev, vector);
+        }
+    }
+}
+
+static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
+                                         bool with_irqfd)
 {
     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
     VirtQueue *vq = virtio_get_queue(proxy->vdev, n);

hw/virtio-pci.c static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign) · line 620

Quoted 5 lines
hw/virtio-pci.c +1 -1
@@ -592,9 +617,9 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign)
         if (r < 0) {
             return r;
         }
-        virtio_queue_set_guest_notifier_fd_handler(vq, true, false);
+        virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);

+ virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd);

Quoted 7 lines

hw/virtio-pci.c static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign) · line 622

Quoted 3 lines
hw/virtio-pci.c +1 -1
     } else {
-        virtio_queue_set_guest_notifier_fd_handler(vq, false, false);
+        virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);

+ virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd);

Use the 'assign' variable instead of the constants?

I don't care either way (this is within if (assign)). But all this patch does is add a parameter, unrelated code refactorings should be separate.

Quoted 56 lines
Quoted 52 lines
hw/virtio-pci.c +8 -5
         event_notifier_cleanup(notifier);
     }
 
@@ -612,9 +637,11 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign)
     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
     VirtIODevice *vdev = proxy->vdev;
     int r, n;
+    bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
+        kvm_msi_via_irqfd_enabled();
 
     /* Must unset vector notifier while guest notifier is still assigned */
-    if (kvm_msi_via_irqfd_enabled() && !assign) {
+    if (with_irqfd && !assign) {
         msix_unset_vector_notifiers(&proxy->pci_dev);
         g_free(proxy->vector_irqfd);
         proxy->vector_irqfd = NULL;
@@ -625,21 +652,22 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign)
             break;
         }
 
-        r = virtio_pci_set_guest_notifier(d, n, assign);
+        r = virtio_pci_set_guest_notifier(d, n, assign,
+                                          kvm_msi_via_irqfd_enabled());
         if (r < 0) {
             goto assign_error;
         }
     }
 
     /* Must set vector notifier after guest notifier has been assigned */
-    if (kvm_msi_via_irqfd_enabled() && assign) {
+    if (with_irqfd && assign) {
         proxy->vector_irqfd =
             g_malloc0(sizeof(*proxy->vector_irqfd) *
                       msix_nr_vectors_allocated(&proxy->pci_dev));
         r = msix_set_vector_notifiers(&proxy->pci_dev,
                                       kvm_virtio_pci_vector_use,
                                       kvm_virtio_pci_vector_release,
-                                      NULL);
+                                      kvm_virtio_pci_vector_poll);
         if (r < 0) {
             goto assign_error;
         }
@@ -651,7 +679,7 @@ assign_error:
     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
     assert(assign);
     while (--n >= 0) {
-        virtio_pci_set_guest_notifier(d, n, !assign);
+        virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
     }
     return r;
 }
Signature · 1 line
Asias
#6 lore raw

Re: [PATCH 3/3] virtio-pci: don't poll masked vectors

In reply to Michael S. Tsirkin
Quoted 16 lines · Michael S. Tsirkin
hw/virtio-pci.c +15 -1
-static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign)
+static void kvm_virtio_pci_vector_poll(PCIDevice *dev,
+                                       unsigned int vector_start,
+                                       unsigned int vector_end)
+{
+    VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
+    VirtIODevice *vdev = proxy->vdev;
+    int queue_no;
+    unsigned int vector;
+    EventNotifier *notifier;
+    VirtQueue *vq;
+
+    for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) {
+        if (!virtio_queue_get_num(vdev, queue_no)) {
+            break;
+        }

hw/virtio-pci.c static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector) · line 604

Quoted 10 lines
hw/virtio-pci.c +10 -0
+        vector = virtio_queue_vector(vdev, queue_no);
+        if (vector < vector_start || vector >= vector_end ||
+            !msix_is_masked(dev, vector)) {
+            continue;
+        }
+        vq = virtio_get_queue(vdev, queue_no);
+        notifier = virtio_queue_get_guest_notifier(vq);
+        if (event_notifier_test_and_clear(notifier)) {
+            msix_set_pending(dev, vector);
+        }

Small difference to virtio_queue_guest_notifier_read() here: we do not set vq->vdev->isr |= 0x01. I guess no guest drivers use isr with MSIX but should we still set it or even just call virtio_queue_guest_notifier_read() instead of duplicating that event notifier read here?

Stefan

#7 lore raw
In reply to Michael S. Tsirkin
Quoted 10 lines · Michael S. Tsirkin

At the moment when vector is masked virtio will poll it in userspace, even if it is handled by irqfd.
This is done in order to update pending bits, but it's not really required until someone reads the pending bits. On the other hand this read results in extra io thread wakeups.

As we only implement the pending bits as a compatibility feature (read - real drivers don't use it), we can defer the irqfd poll until the read actually happens.

Quoted 7 lines

This does not seem to affect vhost-net speed
in simple benchmarks but could help block: both vhost-blk and dataplane when using irqfd,
and I also think this is cleaner than enabling/disabling notifiers all the time.

This will also be the basis for future optimizations.

Note: this is on top of the typesafe bindings patch v3 I sent previously.
You can get the whole bundle from:
git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git pci

Signature · 1 line
MST
#8 lore raw
In reply to Michael S. Tsirkin
Quoted 23 lines · Michael S. Tsirkin

At the moment when vector is masked virtio will poll it in userspace, even if it is handled by irqfd.
This is done in order to update pending bits, but it's not really required until someone reads the pending bits. On the other hand this read results in extra io thread wakeups.

As we only implement the pending bits as a compatibility feature (read - real drivers don't use it), we can defer the irqfd poll until the read actually happens.

This does not seem to affect vhost-net speed
in simple benchmarks but could help block: both vhost-blk and dataplane when using irqfd,
and I also think this is cleaner than enabling/disabling notifiers all the time.

This will also be the basis for future optimizations.

Michael S. Tsirkin (3):
msi: add API to get notified about pending bit poll
msix: expose access to masked/pending state
virtio-pci: don't poll masked vectors

Quoted 6 lines
 hw/pci/msix.c   | 19 +++++++++++++++----
 hw/pci/msix.h   |  6 +++++-
 hw/pci/pci.h    |  4 ++++
 hw/vfio_pci.c   |  2 +-
 hw/virtio-pci.c | 53 +++++++++++++++++++++++++++++++++++++++++------------
 5 files changed, 66 insertions(+), 18 deletions(-)

The performance boost is significant here. It is close to the result of dropping msix_fire_vector_notifier() hack.

Signature · 1 line
Asias
#9 lore raw
Quoted 31 lines · Asias He
Quoted 23 lines · Michael S. Tsirkin

At the moment when vector is masked virtio will poll it in userspace, even if it is handled by irqfd.
This is done in order to update pending bits, but it's not really required until someone reads the pending bits. On the other hand this read results in extra io thread wakeups.

As we only implement the pending bits as a compatibility feature (read - real drivers don't use it), we can defer the irqfd poll until the read actually happens.

This does not seem to affect vhost-net speed
in simple benchmarks but could help block: both vhost-blk and dataplane when using irqfd,
and I also think this is cleaner than enabling/disabling notifiers all the time.

This will also be the basis for future optimizations.

Michael S. Tsirkin (3):
msi: add API to get notified about pending bit poll
msix: expose access to masked/pending state
virtio-pci: don't poll masked vectors

Quoted 6 lines
 hw/pci/msix.c   | 19 +++++++++++++++----
 hw/pci/msix.h   |  6 +++++-
 hw/pci/pci.h    |  4 ++++
 hw/vfio_pci.c   |  2 +-
 hw/virtio-pci.c | 53 +++++++++++++++++++++++++++++++++++++++++------------
 5 files changed, 66 insertions(+), 18 deletions(-)
Quoted 2 lines

The performance boost is significant here. It is close to the result of dropping msix_fire_vector_notifier() hack.

Okay great. I have one other last optimization up my sleeve, that should hopefully make it as fast as with the hack.

Quoted 2 lines
Signature · 1 line
Asias