Hi,
This patches try to support multi virtual queues(multi-vq) in one
virtio-blk device, and maps each virtual queue(vq) to blk-mq's
hardware queue.
With this approach, both scalability and performance problems on
virtio-blk device get improved.
For verifying the improvement, I implements virtio-blk multi-vq over
qemu's dataplane feature, and both handling host notification
from each vq and processing host I/O are still kept in the per-device
iothread context, the changes are based on qemu v2.0.0 release, and
can be accessed from below tree:
git://kernel.ubuntu.com/ming/qemu.git #v2.0.0-virtblk-dataplane-mq
For enabling the multi-vq feature, 'num_queues=N' need to be added into
'-device virtio-blk-pci ...' of qemu command line, and suggest to pass
'vectors=N+1' to keep one MSI irq vector per each vq, and the feature
depends on x-data-plane.
Fio(libaio, randread, iodepth=64, bs=4K, jobs=N) is run inside VM to
verify the improvement.
I just create a small quadcore VM and run fio inside the VM, and
num_queues of the virtio-blk device is set as 2, but looks the
improvement is still obvious.
1), about scalability
- without mutli-vq feature
-- jobs=2, thoughput: 145K iops
-- jobs=4, thoughput: 100K iops
- without mutli-vq feature
-- jobs=2, thoughput: 186K iops
-- jobs=4, thoughput: 199K iops
2), about thoughput
- without mutli-vq feature
-- top thoughput: 145K iops
- with mutli-vq feature
-- top thoughput: 199K iops
So even for one quadcore VM, if the virtqueue number is increased
from 1 to 2, both scalability and performance can get improved a
lot.
Thanks,
--
Ming Lei
Current virtio-blk spec only supports one virtual queue for transfering
data between VM and host, and inside VM all kinds of operations on
the virtual queue needs to hold one lock, so cause below problems:
- no scalability
- bad throughput
So this patch requests to introduce feature of VIRTIO_BLK_F_MQ
so that more than one virtual queues can be used to virtio-blk
device, then above problems can be solved or eased.
Signed-off-by: Ming Lei <redacted>
---
include/uapi/linux/virtio_blk.h | 4 ++++
1 file changed, 4 insertions(+)
@@ -40,6 +40,7 @@#define VIRTIO_BLK_F_WCE 9 /* Writeback mode enabled after reset */#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */+#define VIRTIO_BLK_F_MQ 12 /* support more than one vq */#ifndef __KERNEL__/* Old (deprecated) name for VIRTIO_BLK_F_WCE. */
@@ -77,6 +78,9 @@ struct virtio_blk_config {/* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */__u8wce;++/* number of vqs, only available when VIRTIO_BLK_F_MQ is set */+__u16num_queues;}__attribute__((packed));/*
Firstly this patch supports more than one virtual queues for virtio-blk
device.
Secondly this patch maps the virtual queue to blk-mq's hardware queue.
With this approach, both scalability and performance problem can be improved.
Signed-off-by: Ming Lei <redacted>
---
drivers/block/virtio_blk.c | 75 ++++++++++++++++++++++++++++++++------------
1 file changed, 55 insertions(+), 20 deletions(-)
@@ -24,8 +26,8 @@ static struct workqueue_struct *virtblk_wq;structvirtio_blk{structvirtio_device*vdev;-structvirtqueue*vq;-spinlock_tvq_lock;+structvirtqueue*vq[MAX_NUM_VQ];+spinlock_tvq_lock[MAX_NUM_VQ];/* The disk structure for the kernel. */structgendisk*disk;
@@ -47,6 +49,9 @@ struct virtio_blk/* Ida index - used to track minor number allocations. */intindex;++/* num of vqs */+intnum_vqs;};structvirtblk_req
@@ -151,7 +157,7 @@ static void virtblk_done(struct virtqueue *vq)/* In case queue is stopped waiting for more buffers. */if(req_done)blk_mq_start_stopped_hw_queues(vblk->disk->queue,true);-spin_unlock_irqrestore(&vblk->vq_lock,flags);+spin_unlock_irqrestore(&vblk->vq_lock[qid],flags);}staticintvirtio_queue_rq(structblk_mq_hw_ctx*hctx,structrequest*req)
@@ -202,12 +209,12 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)vbr->out_hdr.type|=VIRTIO_BLK_T_IN;}-spin_lock_irqsave(&vblk->vq_lock,flags);-err=__virtblk_add_req(vblk->vq,vbr,vbr->sg,num);+spin_lock_irqsave(&vblk->vq_lock[qid],flags);+err=__virtblk_add_req(vblk->vq[qid],vbr,vbr->sg,num);if(err){-virtqueue_kick(vblk->vq);+virtqueue_kick(vblk->vq[qid]);blk_mq_stop_hw_queue(hctx);-spin_unlock_irqrestore(&vblk->vq_lock,flags);+spin_unlock_irqrestore(&vblk->vq_lock[qid],flags);/* Out of mem doesn't actually happen, since we fall back*todirectdescriptors*/if(err==-ENOMEM||err==-ENOSPC)
@@ -377,12 +384,40 @@ static void virtblk_config_changed(struct virtio_device *vdev)staticintinit_vq(structvirtio_blk*vblk){interr=0;+inti;+vq_callback_t*callbacks[MAX_NUM_VQ];+constchar*names[MAX_NUM_VQ];+unsignedshortnum_vqs;+structvirtio_device*vdev=vblk->vdev;-/* We expect one virtqueue, for output. */-vblk->vq=virtio_find_single_vq(vblk->vdev,virtblk_done,"requests");-if(IS_ERR(vblk->vq))-err=PTR_ERR(vblk->vq);+if(virtio_has_feature(vdev,VIRTIO_BLK_F_MQ))+err=virtio_cread_feature(vdev,VIRTIO_BLK_F_MQ,+structvirtio_blk_config,num_queues,+&num_vqs);+else+num_vqs=1;++if(err)+gotoout;+if(num_vqs>MAX_NUM_VQ)+num_vqs=MAX_NUM_VQ;++for(i=0;i<num_vqs;i++){+callbacks[i]=virtblk_done;+names[i]="requests";+}++/* Discover virtqueues and write information to configuration. */+err=vdev->config->find_vqs(vdev,num_vqs,vblk->vq,+callbacks,names);+if(err)+gotoout;++for(i=0;i<num_vqs;i++)+spin_lock_init(&vblk->vq_lock[i]);+vblk->num_vqs=num_vqs;+out:returnerr;}
@@ -551,7 +586,6 @@ static int virtblk_probe(struct virtio_device *vdev)err=init_vq(vblk);if(err)gotoout_free_vblk;-spin_lock_init(&vblk->vq_lock);/* FIXME: How many partitions? How long is a piece of string? */vblk->disk=alloc_disk(1<<PART_BITS);
@@ -562,7 +596,7 @@ static int virtblk_probe(struct virtio_device *vdev)/* Default queue sizing is to fill the ring. */if(!virtblk_queue_depth){-virtblk_queue_depth=vblk->vq->num_free;+virtblk_queue_depth=vblk->vq[0]->num_free;/* ... but without indirect descs, we use 2 descs per req */if(!virtio_has_feature(vdev,VIRTIO_RING_F_INDIRECT_DESC))virtblk_queue_depth/=2;
@@ -570,7 +604,6 @@ static int virtblk_probe(struct virtio_device *vdev)memset(&vblk->tag_set,0,sizeof(vblk->tag_set));vblk->tag_set.ops=&virtio_mq_ops;-vblk->tag_set.nr_hw_queues=1;vblk->tag_set.queue_depth=virtblk_queue_depth;vblk->tag_set.numa_node=NUMA_NO_NODE;vblk->tag_set.flags=BLK_MQ_F_SHOULD_MERGE;
@@ -578,6 +611,7 @@ static int virtblk_probe(struct virtio_device *vdev)sizeof(structvirtblk_req)+sizeof(structscatterlist)*sg_elems;vblk->tag_set.driver_data=vblk;+vblk->tag_set.nr_hw_queues=vblk->num_vqs;err=blk_mq_alloc_tag_set(&vblk->tag_set);if(err)
Hi,
This patches try to support multi virtual queues(multi-vq) in one
virtio-blk device, and maps each virtual queue(vq) to blk-mq's
hardware queue.
With this approach, both scalability and performance problems on
virtio-blk device get improved.
For verifying the improvement, I implements virtio-blk multi-vq over
qemu's dataplane feature, and both handling host notification
from each vq and processing host I/O are still kept in the per-device
iothread context, the changes are based on qemu v2.0.0 release, and
can be accessed from below tree:
git://kernel.ubuntu.com/ming/qemu.git #v2.0.0-virtblk-dataplane-mq
For enabling the multi-vq feature, 'num_queues=N' need to be added into
'-device virtio-blk-pci ...' of qemu command line, and suggest to pass
'vectors=N+1' to keep one MSI irq vector per each vq, and the feature
depends on x-data-plane.
Fio(libaio, randread, iodepth=64, bs=4K, jobs=N) is run inside VM to
verify the improvement.
I just create a small quadcore VM and run fio inside the VM, and
num_queues of the virtio-blk device is set as 2, but looks the
improvement is still obvious.
1), about scalability
- without mutli-vq feature
-- jobs=2, thoughput: 145K iops
-- jobs=4, thoughput: 100K iops
- without mutli-vq feature
-- jobs=2, thoughput: 186K iops
-- jobs=4, thoughput: 199K iops
Awesome! I was hoping someone would do that, and make virtio-blk take
full advantage of blk-mq.
--
Jens Axboe
From: Rusty Russell <hidden> Date: 2014-06-17 00:44:27
Ming Lei [off-list ref] writes:
quoted hunk
Current virtio-blk spec only supports one virtual queue for transfering
data between VM and host, and inside VM all kinds of operations on
the virtual queue needs to hold one lock, so cause below problems:
- no scalability
- bad throughput
So this patch requests to introduce feature of VIRTIO_BLK_F_MQ
so that more than one virtual queues can be used to virtio-blk
device, then above problems can be solved or eased.
Signed-off-by: Ming Lei <redacted>
---
include/uapi/linux/virtio_blk.h | 4 ++++
1 file changed, 4 insertions(+)
@@ -40,6 +40,7 @@#define VIRTIO_BLK_F_WCE 9 /* Writeback mode enabled after reset */#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */+#define VIRTIO_BLK_F_MQ 12 /* support more than one vq */#ifndef __KERNEL__/* Old (deprecated) name for VIRTIO_BLK_F_WCE. */
@@ -77,6 +78,9 @@ struct virtio_blk_config {/* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */__u8wce;++/* number of vqs, only available when VIRTIO_BLK_F_MQ is set */+__u16num_queues;}__attribute__((packed));
Hmm, please pad this like so:
__u8 unused;
__u16 num_queues;
That avoids weird alignment.
Thanks,
Rusty.
From: Stefan Hajnoczi <hidden> Date: 2014-06-17 02:40:58
On Sat, Jun 14, 2014 at 1:29 AM, Ming Lei [off-list ref] wrote:
quoted hunk
Firstly this patch supports more than one virtual queues for virtio-blk
device.
Secondly this patch maps the virtual queue to blk-mq's hardware queue.
With this approach, both scalability and performance problem can be improved.
Signed-off-by: Ming Lei <redacted>
---
drivers/block/virtio_blk.c | 75 ++++++++++++++++++++++++++++++++------------
1 file changed, 55 insertions(+), 20 deletions(-)
On Tue, Jun 17, 2014 at 10:40 AM, Stefan Hajnoczi [off-list ref] wrote:
On Sat, Jun 14, 2014 at 1:29 AM, Ming Lei [off-list ref] wrote:
quoted
Firstly this patch supports more than one virtual queues for virtio-blk
device.
Secondly this patch maps the virtual queue to blk-mq's hardware queue.
With this approach, both scalability and performance problem can be improved.
Signed-off-by: Ming Lei <redacted>
---
drivers/block/virtio_blk.c | 75 ++++++++++++++++++++++++++++++++------------
1 file changed, 55 insertions(+), 20 deletions(-)
It would be nice to allocate virtqueues dynamically instead of
hardcoding the limit. virtio-scsi also allocates virtqueues
dynamically.
virtio-scsi may have lots of LUN, but virtio-blk only has one disk
which needn't lots of hardware queues.
Also it doesn't matter since it isn't part of ABI.
If change on virtio_blk_config is agreed, both host side and
guest side can choose to support dynamic length or pre-defined
length freely.
Thanks,
--
Ming Lei
From: Paolo Bonzini <pbonzini@redhat.com> Date: 2014-06-17 15:53:36
Il 17/06/2014 17:50, Ming Lei ha scritto:
quoted
quoted
It would be nice to allocate virtqueues dynamically instead of
hardcoding the limit. virtio-scsi also allocates virtqueues
dynamically.
virtio-scsi may have lots of LUN, but virtio-blk only has one disk
which needn't lots of hardware queues.
If you want to do queue steering based on the guest VCPU number, the
number of queues must be = to the number of VCPUs shouldn't it?
I tried using a divisor of the number of VCPUs, but couldn't get the
block layer to deliver interrupts to the right VCPU.
Paolo
On Tue, Jun 17, 2014 at 11:53 PM, Paolo Bonzini [off-list ref] wrote:
Il 17/06/2014 17:50, Ming Lei ha scritto:
quoted
quoted
quoted
It would be nice to allocate virtqueues dynamically instead of
hardcoding the limit. virtio-scsi also allocates virtqueues
dynamically.
virtio-scsi may have lots of LUN, but virtio-blk only has one disk
which needn't lots of hardware queues.
If you want to do queue steering based on the guest VCPU number, the number
of queues must be = to the number of VCPUs shouldn't it?
I tried using a divisor of the number of VCPUs, but couldn't get the block
layer to deliver interrupts to the right VCPU.
For blk-mq's hardware queue, that won't be necessary to equal to
VCPUs number, and irq affinity per hw queue can be simply set as
blk_mq_hw_ctx->cpumask.
Thanks,
--
Ming Lei
From: Paolo Bonzini <pbonzini@redhat.com> Date: 2014-06-17 16:34:26
Il 17/06/2014 18:00, Ming Lei ha scritto:
quoted
quoted
If you want to do queue steering based on the guest VCPU number, the number
of queues must be = to the number of VCPUs shouldn't it?
I tried using a divisor of the number of VCPUs, but couldn't get the block
layer to deliver interrupts to the right VCPU.
For blk-mq's hardware queue, that won't be necessary to equal to
VCPUs number, and irq affinity per hw queue can be simply set as
blk_mq_hw_ctx->cpumask.
Yes, but on top of that you want to have each request processed exactly
by the CPU that sent it. Unless the cpumasks are singletons, most of
the benefit went away in my virtio-scsi tests. Perhaps blk-mq is smarter.
Can you try benchmarking a 16 VCPU guest with 8 and 16 queues?
Paolo
On Wed, Jun 18, 2014 at 12:34 AM, Paolo Bonzini [off-list ref] wrote:
Il 17/06/2014 18:00, Ming Lei ha scritto:
quoted
quoted
quoted
If you want to do queue steering based on the guest VCPU number, the
number
of queues must be = to the number of VCPUs shouldn't it?
I tried using a divisor of the number of VCPUs, but couldn't get the
block
layer to deliver interrupts to the right VCPU.
For blk-mq's hardware queue, that won't be necessary to equal to
VCPUs number, and irq affinity per hw queue can be simply set as
blk_mq_hw_ctx->cpumask.
Yes, but on top of that you want to have each request processed exactly by
the CPU that sent it. Unless the cpumasks are singletons, most of the
benefit went away in my virtio-scsi tests. Perhaps blk-mq is smarter.
Can you try benchmarking a 16 VCPU guest with 8 and 16 queues?
From VM side, it might be better to use one hardware queue per vCPU,
since in theory it can remove vq lock contention.
But from host side, there is still disadvantage with more queues, since
more queues means more notify times, in my virtio-blk test, even with
ioeventfd, one notification may take ~3us averagely on qemu-system-x86_64.
For virtio-blk, I don't think it is always better to take more queues, and
we need to leverage below things in host side:
- host storage top performance, generally it reaches that with more
than 1 jobs with libaio(suppose it is N, so basically we can use N
iothread per device in qemu to try to get top performance)
- iothreads' loading(if iothreads are at full loading, increasing
queues doesn't help at all)
In my test, I only use the current per-dev iothread(x-dataplane)
in qemu to handle 2 vqs' notification and precess all I/O from
the 2 vqs, and looks it can improve IOPS by ~30%.
For virtio-scsi, the current usage doesn't make full use of blk-mq's
advantage too because only one vq is active at the same time, so I
guess the multi vqs' benefit won't be very much and I'd like to post
patches to support that first, then provide test data with
more queues(8, 16).
Thanks,
--
Ming Lei
From: Paolo Bonzini <pbonzini@redhat.com> Date: 2015-12-14 10:31:35
On 18/06/2014 06:04, Ming Lei wrote:
For virtio-blk, I don't think it is always better to take more queues, and
we need to leverage below things in host side:
- host storage top performance, generally it reaches that with more
than 1 jobs with libaio(suppose it is N, so basically we can use N
iothread per device in qemu to try to get top performance)
- iothreads' loading(if iothreads are at full loading, increasing
queues doesn't help at all)
In my test, I only use the current per-dev iothread(x-dataplane)
in qemu to handle 2 vqs' notification and precess all I/O from
the 2 vqs, and looks it can improve IOPS by ~30%.
For virtio-scsi, the current usage doesn't make full use of blk-mq's
advantage too because only one vq is active at the same time, so I
guess the multi vqs' benefit won't be very much and I'd like to post
patches to support that first, then provide test data with
more queues(8, 16).
Hi Ming Lei,
would you like to repost these patches now that MQ support is in the kernel?
Also, I changed my mind about moving linux-aio to AioContext. I now
think it's a good idea, because it limits the number of io_getevents
syscalls. O:-) So I would be happy to review your patches for that as well.
Paolo
Hi Paolo,
On Mon, Dec 14, 2015 at 6:31 PM, Paolo Bonzini [off-list ref] wrote:
On 18/06/2014 06:04, Ming Lei wrote:
quoted
For virtio-blk, I don't think it is always better to take more queues, and
we need to leverage below things in host side:
- host storage top performance, generally it reaches that with more
than 1 jobs with libaio(suppose it is N, so basically we can use N
iothread per device in qemu to try to get top performance)
- iothreads' loading(if iothreads are at full loading, increasing
queues doesn't help at all)
In my test, I only use the current per-dev iothread(x-dataplane)
in qemu to handle 2 vqs' notification and precess all I/O from
the 2 vqs, and looks it can improve IOPS by ~30%.
For virtio-scsi, the current usage doesn't make full use of blk-mq's
advantage too because only one vq is active at the same time, so I
guess the multi vqs' benefit won't be very much and I'd like to post
patches to support that first, then provide test data with
more queues(8, 16).
Hi Ming Lei,
would you like to repost these patches now that MQ support is in the kernel?
Also, I changed my mind about moving linux-aio to AioContext. I now
think it's a good idea, because it limits the number of io_getevents
syscalls. O:-) So I would be happy to review your patches for that as well.
OK, I try to figure out a new version, and it might take a while since it is
close to festival season, :-)
Thanks,