Skip to content

Commit

Permalink
virtio: don't enable notifications during polling
Browse files Browse the repository at this point in the history
Virtqueue notifications are not necessary during polling, so we disable
them.  This allows the guest driver to avoid MMIO vmexits.
Unfortunately the virtio-blk and virtio-scsi handler functions re-enable
notifications, defeating this optimization.

Fix virtio-blk and virtio-scsi emulation so they leave notifications
disabled.  The key thing to remember for correctness is that polling
always checks one last time after ending its loop, therefore it's safe
to lose the race when re-enabling notifications at the end of polling.

There is a measurable performance improvement of 5-10% with the null-co
block driver.  Real-life storage configurations will see a smaller
improvement because the MMIO vmexit overhead contributes less to
latency.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <20191209210957.65087-1-stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
  • Loading branch information
stefanhaRH authored and mstsirkin committed Jan 5, 2020
1 parent 6620801 commit d0435bc
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 10 deletions.
9 changes: 7 additions & 2 deletions hw/block/virtio-blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -764,13 +764,16 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
{
VirtIOBlockReq *req;
MultiReqBuffer mrb = {};
bool suppress_notifications = virtio_queue_get_notification(vq);
bool progress = false;

aio_context_acquire(blk_get_aio_context(s->blk));
blk_io_plug(s->blk);

do {
virtio_queue_set_notification(vq, 0);
if (suppress_notifications) {
virtio_queue_set_notification(vq, 0);
}

while ((req = virtio_blk_get_request(s, vq))) {
progress = true;
Expand All @@ -781,7 +784,9 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
}
}

virtio_queue_set_notification(vq, 1);
if (suppress_notifications) {
virtio_queue_set_notification(vq, 1);
}
} while (!virtio_queue_empty(vq));

if (mrb.num_reqs) {
Expand Down
9 changes: 7 additions & 2 deletions hw/scsi/virtio-scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -597,12 +597,15 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
{
VirtIOSCSIReq *req, *next;
int ret = 0;
bool suppress_notifications = virtio_queue_get_notification(vq);
bool progress = false;

QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);

do {
virtio_queue_set_notification(vq, 0);
if (suppress_notifications) {
virtio_queue_set_notification(vq, 0);
}

while ((req = virtio_scsi_pop_req(s, vq))) {
progress = true;
Expand All @@ -622,7 +625,9 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
}
}

virtio_queue_set_notification(vq, 1);
if (suppress_notifications) {
virtio_queue_set_notification(vq, 1);
}
} while (ret != -EINVAL && !virtio_queue_empty(vq));

QTAILQ_FOREACH_SAFE(req, &reqs, next, next) {
Expand Down
12 changes: 6 additions & 6 deletions hw/virtio/virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,11 @@ static void virtio_queue_packed_set_notification(VirtQueue *vq, int enable)
}
}

bool virtio_queue_get_notification(VirtQueue *vq)
{
return vq->notification;
}

void virtio_queue_set_notification(VirtQueue *vq, int enable)
{
vq->notification = enable;
Expand Down Expand Up @@ -3410,17 +3415,12 @@ static bool virtio_queue_host_notifier_aio_poll(void *opaque)
{
EventNotifier *n = opaque;
VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
bool progress;

if (!vq->vring.desc || virtio_queue_empty(vq)) {
return false;
}

progress = virtio_queue_notify_aio_vq(vq);

/* In case the handler function re-enabled notifications */
virtio_queue_set_notification(vq, 0);
return progress;
return virtio_queue_notify_aio_vq(vq);
}

static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n)
Expand Down
1 change: 1 addition & 0 deletions include/hw/virtio/virtio.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id);

void virtio_notify_config(VirtIODevice *vdev);

bool virtio_queue_get_notification(VirtQueue *vq);
void virtio_queue_set_notification(VirtQueue *vq, int enable);

int virtio_queue_ready(VirtQueue *vq);
Expand Down

0 comments on commit d0435bc

Please sign in to comment.