aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Maximets <i.maximets@ovn.org>2023-09-27 15:50:33 +0200
committerMichael S. Tsirkin <mst@redhat.com>2023-10-04 18:15:06 -0400
commit850cd20b072cd330cb24aa1c92732b9722998d40 (patch)
tree1d605e3c657b1eee2cba4bb66e1fbffe23eb88b0
parenta6f4d2ec42f3feb6c399f5760a2567ca78897bd7 (diff)
downloadqemu-850cd20b072cd330cb24aa1c92732b9722998d40.zip
qemu-850cd20b072cd330cb24aa1c92732b9722998d40.tar.gz
qemu-850cd20b072cd330cb24aa1c92732b9722998d40.tar.bz2
virtio: use shadow_avail_idx while checking number of heads
We do not need the most up to date number of heads, we only want to know if there is at least one. Use shadow variable as long as it is not equal to the last available index checked. This avoids expensive qatomic dereference of the RCU-protected memory region cache as well as the memory access itself. The change improves performance of the af-xdp network backend by 2-3%. Signed-off-by: Ilya Maximets <i.maximets@ovn.org> Message-Id: <20230927135157.2316982-1-i.maximets@ovn.org> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r--hw/virtio/virtio.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index c727e92..2058b83 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -997,7 +997,12 @@ void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
/* Called within rcu_read_lock(). */
static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
{
- uint16_t num_heads = vring_avail_idx(vq) - idx;
+ uint16_t avail_idx, num_heads;
+
+ /* Use shadow index whenever possible. */
+ avail_idx = (vq->shadow_avail_idx != idx) ? vq->shadow_avail_idx
+ : vring_avail_idx(vq);
+ num_heads = avail_idx - idx;
/* Check it isn't doing very strange things with descriptor numbers. */
if (num_heads > vq->vring.num) {
@@ -1005,8 +1010,15 @@ static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
idx, vq->shadow_avail_idx);
return -EINVAL;
}
- /* On success, callers read a descriptor at vq->last_avail_idx.
- * Make sure descriptor read does not bypass avail index read. */
+ /*
+ * On success, callers read a descriptor at vq->last_avail_idx.
+ * Make sure descriptor read does not bypass avail index read.
+ *
+ * This is necessary even if we are using a shadow index, since
+ * the shadow index could have been initialized by calling
+ * vring_avail_idx() outside of this function, i.e., by a guest
+ * memory read not accompanied by a barrier.
+ */
if (num_heads) {
smp_rmb();
}