aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2016-12-12 01:46:49 -0500
committerMichael S. Tsirkin <mst@redhat.com>2016-12-15 17:12:50 -0500
commit809ecb9bca6a9424ccd392d67e368160f8b76c92 (patch)
tree606dee0e521208955dee5b5bdda763b3c30425cb
parent6c083c2b8a0a110cad936bc0a2c089f0d8115175 (diff)
vhost: cache used event for better performance
When event index was enabled, we need to fetch used event from userspace memory each time. This userspace fetch (with memory barrier) could be saved sometime when 1) caching used event and 2) if used event is ahead of new and old to new updating does not cross it, we're sure there's no need to notify guest. This will be useful for heavy tx load e.g guest pktgen test with Linux driver shows ~3.5% improvement. Signed-off-by: Jason Wang <jasowang@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r--drivers/vhost/vhost.c28
-rw-r--r--drivers/vhost/vhost.h3
2 files changed, 25 insertions, 6 deletions
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 2f58181b918d..c0f81e8cb50c 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -290,6 +290,7 @@ static void vhost_vq_reset(struct vhost_dev *dev,
290 vq->avail = NULL; 290 vq->avail = NULL;
291 vq->used = NULL; 291 vq->used = NULL;
292 vq->last_avail_idx = 0; 292 vq->last_avail_idx = 0;
293 vq->last_used_event = 0;
293 vq->avail_idx = 0; 294 vq->avail_idx = 0;
294 vq->last_used_idx = 0; 295 vq->last_used_idx = 0;
295 vq->signalled_used = 0; 296 vq->signalled_used = 0;
@@ -1324,7 +1325,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
1324 r = -EINVAL; 1325 r = -EINVAL;
1325 break; 1326 break;
1326 } 1327 }
1327 vq->last_avail_idx = s.num; 1328 vq->last_avail_idx = vq->last_used_event = s.num;
1328 /* Forget the cached index value. */ 1329 /* Forget the cached index value. */
1329 vq->avail_idx = vq->last_avail_idx; 1330 vq->avail_idx = vq->last_avail_idx;
1330 break; 1331 break;
@@ -2159,10 +2160,6 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
2159 __u16 old, new; 2160 __u16 old, new;
2160 __virtio16 event; 2161 __virtio16 event;
2161 bool v; 2162 bool v;
2162 /* Flush out used index updates. This is paired
2163 * with the barrier that the Guest executes when enabling
2164 * interrupts. */
2165 smp_mb();
2166 2163
2167 if (vhost_has_feature(vq, VIRTIO_F_NOTIFY_ON_EMPTY) && 2164 if (vhost_has_feature(vq, VIRTIO_F_NOTIFY_ON_EMPTY) &&
2168 unlikely(vq->avail_idx == vq->last_avail_idx)) 2165 unlikely(vq->avail_idx == vq->last_avail_idx))
@@ -2170,6 +2167,10 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
2170 2167
2171 if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) { 2168 if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) {
2172 __virtio16 flags; 2169 __virtio16 flags;
2170 /* Flush out used index updates. This is paired
2171 * with the barrier that the Guest executes when enabling
2172 * interrupts. */
2173 smp_mb();
2173 if (vhost_get_user(vq, flags, &vq->avail->flags)) { 2174 if (vhost_get_user(vq, flags, &vq->avail->flags)) {
2174 vq_err(vq, "Failed to get flags"); 2175 vq_err(vq, "Failed to get flags");
2175 return true; 2176 return true;
@@ -2184,11 +2185,26 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
2184 if (unlikely(!v)) 2185 if (unlikely(!v))
2185 return true; 2186 return true;
2186 2187
2188 /* We're sure if the following conditions are met, there's no
2189 * need to notify guest:
2190 * 1) cached used event is ahead of new
2191 * 2) old to new updating does not cross cached used event. */
2192 if (vring_need_event(vq->last_used_event, new + vq->num, new) &&
2193 !vring_need_event(vq->last_used_event, new, old))
2194 return false;
2195
2196 /* Flush out used index updates. This is paired
2197 * with the barrier that the Guest executes when enabling
2198 * interrupts. */
2199 smp_mb();
2200
2187 if (vhost_get_user(vq, event, vhost_used_event(vq))) { 2201 if (vhost_get_user(vq, event, vhost_used_event(vq))) {
2188 vq_err(vq, "Failed to get used event idx"); 2202 vq_err(vq, "Failed to get used event idx");
2189 return true; 2203 return true;
2190 } 2204 }
2191 return vring_need_event(vhost16_to_cpu(vq, event), new, old); 2205 vq->last_used_event = vhost16_to_cpu(vq, event);
2206
2207 return vring_need_event(vq->last_used_event, new, old);
2192} 2208}
2193 2209
2194/* This actually signals the guest, using eventfd. */ 2210/* This actually signals the guest, using eventfd. */
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 78f3c5fc02e4..a9cbbb148f46 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -107,6 +107,9 @@ struct vhost_virtqueue {
107 /* Last index we used. */ 107 /* Last index we used. */
108 u16 last_used_idx; 108 u16 last_used_idx;
109 109
110 /* Last used evet we've seen */
111 u16 last_used_event;
112
110 /* Used flags */ 113 /* Used flags */
111 u16 used_flags; 114 u16 used_flags;
112 115