Skip to content

Commit

Permalink
vhost: cache used event for better performance
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jason Wang authored and Michael S. Tsirkin committed Dec 15, 2016
1 parent 6c083c2 commit 809ecb9
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 6 deletions.
28 changes: 22 additions & 6 deletions drivers/vhost/vhost.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ static void vhost_vq_reset(struct vhost_dev *dev,
vq->avail = NULL;
vq->used = NULL;
vq->last_avail_idx = 0;
vq->last_used_event = 0;
vq->avail_idx = 0;
vq->last_used_idx = 0;
vq->signalled_used = 0;
Expand Down Expand Up @@ -1324,7 +1325,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
r = -EINVAL;
break;
}
vq->last_avail_idx = s.num;
vq->last_avail_idx = vq->last_used_event = s.num;
/* Forget the cached index value. */
vq->avail_idx = vq->last_avail_idx;
break;
Expand Down Expand Up @@ -2159,17 +2160,17 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
__u16 old, new;
__virtio16 event;
bool v;
/* Flush out used index updates. This is paired
* with the barrier that the Guest executes when enabling
* interrupts. */
smp_mb();

if (vhost_has_feature(vq, VIRTIO_F_NOTIFY_ON_EMPTY) &&
unlikely(vq->avail_idx == vq->last_avail_idx))
return true;

if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) {
__virtio16 flags;
/* Flush out used index updates. This is paired
* with the barrier that the Guest executes when enabling
* interrupts. */
smp_mb();
if (vhost_get_user(vq, flags, &vq->avail->flags)) {
vq_err(vq, "Failed to get flags");
return true;
Expand All @@ -2184,11 +2185,26 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
if (unlikely(!v))
return true;

/* We're sure if the following conditions are met, there's no
* need to notify guest:
* 1) cached used event is ahead of new
* 2) old to new updating does not cross cached used event. */
if (vring_need_event(vq->last_used_event, new + vq->num, new) &&
!vring_need_event(vq->last_used_event, new, old))
return false;

/* Flush out used index updates. This is paired
* with the barrier that the Guest executes when enabling
* interrupts. */
smp_mb();

if (vhost_get_user(vq, event, vhost_used_event(vq))) {
vq_err(vq, "Failed to get used event idx");
return true;
}
return vring_need_event(vhost16_to_cpu(vq, event), new, old);
vq->last_used_event = vhost16_to_cpu(vq, event);

return vring_need_event(vq->last_used_event, new, old);
}

/* This actually signals the guest, using eventfd. */
Expand Down
3 changes: 3 additions & 0 deletions drivers/vhost/vhost.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ struct vhost_virtqueue {
/* Last index we used. */
u16 last_used_idx;

/* Last used evet we've seen */
u16 last_used_event;

/* Used flags */
u16 used_flags;

Expand Down

0 comments on commit 809ecb9

Please sign in to comment.