It isn't necessery to notify guest each time when one request is completed, and it should be enough to just notify one time for each running of virtio_scsi_iothread_handle_cmd().
This patch supresses about 30K/sec write on eventfd. Signed-off-by: Ming Lei <ming....@canonical.com> --- hw/scsi/virtio-scsi-dataplane.c | 4 +++- hw/scsi/virtio-scsi.c | 26 +++++++++++++++++++++++++- include/hw/virtio/virtio-scsi.h | 4 ++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index df17229..294515a 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -62,6 +62,7 @@ static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s, aio_set_event_notifier(s->ctx, &r->host_notifier, handler); r->parent = s; + r->qid = n; if (!vring_setup(&r->vring, VIRTIO_DEVICE(s), n)) { fprintf(stderr, "virtio-scsi: VRing setup failed\n"); @@ -95,7 +96,8 @@ void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req) { vring_push(&req->vring->vring, &req->elem, req->qsgl.size + req->resp_iov.size); - event_notifier_set(&req->vring->guest_notifier); + req->dev->pending_guest_notify |= 1 << (req->vring->qid - 2); + qemu_bh_schedule(req->dev->guest_notify_bh); } static void virtio_scsi_iothread_handle_ctrl(EventNotifier *notifier) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 6e34a2c..98411ef 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -86,6 +86,21 @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req) virtio_scsi_free_req(req); } +static void notify_guest_bh(void *opaque) +{ + VirtIOSCSI *s = opaque; + unsigned int qid; + uint64_t pending = s->pending_guest_notify; + + s->pending_guest_notify = 0; + + while ((qid = ffsl(pending))) { + qid--; + event_notifier_set(&s->cmd_vrings[qid]->guest_notifier); + pending &= ~(1 << qid); + } +} + static void virtio_scsi_bad_req(void) { error_report("wrong size for virtio-scsi headers"); @@ -824,7 +839,12 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, } if (s->conf.iothread) { - virtio_scsi_set_iothread(VIRTIO_SCSI(s), s->conf.iothread); + VirtIOSCSI *vis = VIRTIO_SCSI(s); + + QEMU_BUILD_BUG_ON(VIRTIO_PCI_QUEUE_MAX > 64); + virtio_scsi_set_iothread(vis, s->conf.iothread); + vis->pending_guest_notify = 0; + vis->guest_notify_bh = aio_bh_new(vis->ctx, notify_guest_bh, vis); } } @@ -901,7 +921,11 @@ void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); + VirtIOSCSI *s = VIRTIO_SCSI(vs); + if (vs->conf.iothread) { + qemu_bh_delete(s->guest_notify_bh); + } g_free(vs->cmd_vqs); virtio_cleanup(vdev); } diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 9e1a49c..5e6c57e 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -163,6 +163,7 @@ typedef struct { Vring vring; EventNotifier host_notifier; EventNotifier guest_notifier; + uint32_t qid; } VirtIOSCSIVring; typedef struct VirtIOSCSICommon { @@ -198,6 +199,9 @@ typedef struct VirtIOSCSI { bool dataplane_fenced; Error *blocker; Notifier migration_state_notifier; + + QEMUBH *guest_notify_bh; + uint64_t pending_guest_notify; } VirtIOSCSI; typedef struct VirtIOSCSIReq { -- 1.7.9.5