Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will use indirect
descriptors even if we have plenty of space in the ring. This means that
we take a performance hit at all times due to the overhead of creating
indirect descriptors.
Instead, use it only after we're below a configurable offset.
Signed-off-by: Sasha Levin <redacted>
---
drivers/block/virtio_blk.c | 4 ++++
drivers/char/hw_random/virtio-rng.c | 4 ++++
drivers/char/virtio_console.c | 4 ++++
drivers/net/virtio_net.c | 4 ++++
drivers/virtio/virtio_balloon.c | 4 ++++
drivers/virtio/virtio_ring.c | 21 +++++++++++++++------
include/linux/virtio.h | 1 +
net/9p/trans_virtio.c | 4 ++++
8 files changed, 40 insertions(+), 6 deletions(-)
@@ -93,6 +96,7 @@ static int probe_common(struct virtio_device *vdev)interr;/* We expect a single virtqueue. */+vdev->indirect_thresh=indirect_thresh;vq=virtio_find_single_vq(vdev,random_recv_done,"input");if(IS_ERR(vq))returnPTR_ERR(vq);
@@ -87,8 +87,11 @@ struct vring_virtqueue/* Other side has made a mess, don't try any more. */boolbroken;-/* Host supports indirect buffers */-boolindirect;+/*+*Min.numberoffreespaceintheringtotriggerdirect+*descriptoruse+*/+unsignedintindirect_thresh;/* Host publishes avail event idx */boolevent;
@@ -216,9 +219,12 @@ int virtqueue_add_buf(struct virtqueue *_vq,}#endif-/* If the host supports indirect descriptor tables, and we have multiple-*buffers,thengoindirect.FIXME:tunethisthreshold*/-if(vq->indirect&&(out+in)>1&&vq->num_free){+/*+*Ifthehostsupportsindirectdescriptortables,andwehavemultiple+*buffers,thengoindirect.+*/+if((out+in)>1&&vq->num_free&&+(vq->num_free<vq->indirect_thresh)){head=vring_add_indirect(vq,sg,out,in,gfp);if(likely(head>=0))gotoadd_head;
@@ -647,13 +653,16 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,vq->broken=false;vq->last_used_idx=0;vq->num_added=0;+vq->indirect_thresh=0;list_add_tail(&vq->vq.list,&vdev->vqs);#ifdef DEBUGvq->in_use=false;vq->last_add_time_valid=false;#endif-vq->indirect=virtio_has_feature(vdev,VIRTIO_RING_F_INDIRECT_DESC);+if(virtio_has_feature(vdev,VIRTIO_RING_F_INDIRECT_DESC))+vq->indirect_thresh=vdev->indirect_thresh;+vq->event=virtio_has_feature(vdev,VIRTIO_RING_F_EVENT_IDX);/* No callback? Tell other side not to bother us. */
@@ -69,6 +69,7 @@ struct virtio_device {/* Note that this is a Linux set_bit-style bitmap. */unsignedlongfeatures[1];void*priv;+unsignedintindirect_thresh;};#define dev_to_virtio(dev) container_of(dev, struct virtio_device, dev)
@@ -52,6 +52,9 @@#define VIRTQUEUE_NUM 128+staticunsignedintindirect_thresh;+module_param(indirect_thresh,uint,S_IRUGO);+/* a single mutex to manage channel initialization and attachment */staticDEFINE_MUTEX(virtio_9p_lock);staticDECLARE_WAIT_QUEUE_HEAD(vp_wq);
@@ -501,6 +504,7 @@ static int p9_virtio_probe(struct virtio_device *vdev)chan->vdev=vdev;/* We expect one virtqueue, for requests. */+vdev->indirect_thresh=indirect_thresh;chan->vq=virtio_find_single_vq(vdev,req_done,"requests");if(IS_ERR(chan->vq)){err=PTR_ERR(chan->vq);
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
---
Changes in v2:
- Free correctly indirect buffers.
drivers/block/virtio_blk.c | 4 ++++
drivers/char/hw_random/virtio-rng.c | 4 ++++
drivers/char/virtio_console.c | 4 ++++
drivers/net/virtio_net.c | 4 ++++
drivers/virtio/virtio_balloon.c | 4 ++++
drivers/virtio/virtio_ring.c | 28 ++++++++++++++++++++++++----
include/linux/virtio.h | 1 +
net/9p/trans_virtio.c | 5 +++++
8 files changed, 50 insertions(+), 4 deletions(-)
@@ -97,6 +100,7 @@ static int probe_common(struct virtio_device *vdev)/* We expect a single virtqueue. */vdev->indirect_thresh=indirect_thresh;+vdev->indirect_alloc_thresh=indirect_alloc_thresh;vq=virtio_find_single_vq(vdev,random_recv_done,"input");if(IS_ERR(vq))returnPTR_ERR(vq);
@@ -55,6 +55,9 @@staticunsignedintindirect_thresh;module_param(indirect_thresh,uint,S_IRUGO);+staticunsignedintindirect_alloc_thresh;+module_param(indirect_alloc_thresh,uint,S_IRUGO);+/* a single mutex to manage channel initialization and attachment */staticDEFINE_MUTEX(virtio_9p_lock);staticDECLARE_WAIT_QUEUE_HEAD(vp_wq);
@@ -505,6 +508,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)/* We expect one virtqueue, for requests. */vdev->indirect_thresh=indirect_thresh;+vdev->indirect_alloc_thresh=indirect_alloc_thresh;+chan->vq=virtio_find_single_vq(vdev,req_done,"requests");if(IS_ERR(chan->vq)){err=PTR_ERR(chan->vq);
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-08-28 13:19:12
On Tue, Aug 28, 2012 at 03:04:02PM +0200, Sasha Levin wrote:
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will use indirect
descriptors even if we have plenty of space in the ring. This means that
we take a performance hit at all times due to the overhead of creating
indirect descriptors.
Instead, use it only after we're below a configurable offset.
Signed-off-by: Sasha Levin <redacted>
@@ -93,6 +96,7 @@ static int probe_common(struct virtio_device *vdev)interr;/* We expect a single virtqueue. */+vdev->indirect_thresh=indirect_thresh;vq=virtio_find_single_vq(vdev,random_recv_done,"input");if(IS_ERR(vq))returnPTR_ERR(vq);
@@ -87,8 +87,11 @@ struct vring_virtqueue/* Other side has made a mess, don't try any more. */boolbroken;-/* Host supports indirect buffers */-boolindirect;+/*+*Min.numberoffreespaceintheringtotriggerdirect+*descriptoruse+*/+unsignedintindirect_thresh;/* Host publishes avail event idx */boolevent;
@@ -216,9 +219,12 @@ int virtqueue_add_buf(struct virtqueue *_vq,}#endif-/* If the host supports indirect descriptor tables, and we have multiple-*buffers,thengoindirect.FIXME:tunethisthreshold*/-if(vq->indirect&&(out+in)>1&&vq->num_free){+/*+*Ifthehostsupportsindirectdescriptortables,andwehavemultiple+*buffers,thengoindirect.+*/+if((out+in)>1&&vq->num_free&&+(vq->num_free<vq->indirect_thresh)){head=vring_add_indirect(vq,sg,out,in,gfp);if(likely(head>=0))gotoadd_head;
@@ -647,13 +653,16 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,vq->broken=false;vq->last_used_idx=0;vq->num_added=0;+vq->indirect_thresh=0;list_add_tail(&vq->vq.list,&vdev->vqs);#ifdef DEBUGvq->in_use=false;vq->last_add_time_valid=false;#endif-vq->indirect=virtio_has_feature(vdev,VIRTIO_RING_F_INDIRECT_DESC);+if(virtio_has_feature(vdev,VIRTIO_RING_F_INDIRECT_DESC))+vq->indirect_thresh=vdev->indirect_thresh;+vq->event=virtio_has_feature(vdev,VIRTIO_RING_F_EVENT_IDX);/* No callback? Tell other side not to bother us. */
@@ -69,6 +69,7 @@ struct virtio_device {/* Note that this is a Linux set_bit-style bitmap. */unsignedlongfeatures[1];void*priv;+unsignedintindirect_thresh;};#define dev_to_virtio(dev) container_of(dev, struct virtio_device, dev)
@@ -52,6 +52,9 @@#define VIRTQUEUE_NUM 128+staticunsignedintindirect_thresh;+module_param(indirect_thresh,uint,S_IRUGO);+/* a single mutex to manage channel initialization and attachment */staticDEFINE_MUTEX(virtio_9p_lock);staticDECLARE_WAIT_QUEUE_HEAD(vp_wq);
@@ -501,6 +504,7 @@ static int p9_virtio_probe(struct virtio_device *vdev)chan->vdev=vdev;/* We expect one virtqueue, for requests. */+vdev->indirect_thresh=indirect_thresh;chan->vq=virtio_find_single_vq(vdev,req_done,"requests");if(IS_ERR(chan->vq)){err=PTR_ERR(chan->vq);
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-08-28 13:19:22
On Tue, Aug 28, 2012 at 03:04:03PM +0200, Sasha Levin wrote:
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
@@ -97,6 +100,7 @@ static int probe_common(struct virtio_device *vdev)/* We expect a single virtqueue. */vdev->indirect_thresh=indirect_thresh;+vdev->indirect_alloc_thresh=indirect_alloc_thresh;vq=virtio_find_single_vq(vdev,random_recv_done,"input");if(IS_ERR(vq))returnPTR_ERR(vq);
@@ -55,6 +55,9 @@staticunsignedintindirect_thresh;module_param(indirect_thresh,uint,S_IRUGO);+staticunsignedintindirect_alloc_thresh;+module_param(indirect_alloc_thresh,uint,S_IRUGO);+/* a single mutex to manage channel initialization and attachment */staticDEFINE_MUTEX(virtio_9p_lock);staticDECLARE_WAIT_QUEUE_HEAD(vp_wq);
@@ -505,6 +508,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)/* We expect one virtqueue, for requests. */vdev->indirect_thresh=indirect_thresh;+vdev->indirect_alloc_thresh=indirect_alloc_thresh;+chan->vq=virtio_find_single_vq(vdev,req_done,"requests");if(IS_ERR(chan->vq)){err=PTR_ERR(chan->vq);
On Tue, Aug 28, 2012 at 03:04:03PM +0200, Sasha Levin wrote:
quoted
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
I imagine this helps performance? Any numbers?
I ran benchmarks on the original RFC, I've re-tested it now and got similar
numbers to the original ones (virtio-net using vhost-net, thresh=16):
Before:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 4512.12
After:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 5399.18
Thanks,
Sasha
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-08-29 11:21:41
On Tue, Aug 28, 2012 at 03:35:00PM +0200, Sasha Levin wrote:
On 08/28/2012 03:20 PM, Michael S. Tsirkin wrote:
quoted
On Tue, Aug 28, 2012 at 03:04:03PM +0200, Sasha Levin wrote:
quoted
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
I imagine this helps performance? Any numbers?
I ran benchmarks on the original RFC, I've re-tested it now and got similar
numbers to the original ones (virtio-net using vhost-net, thresh=16):
Before:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 4512.12
After:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 5399.18
Thanks,
Sasha
This is with both patches 1 + 2?
Sorry could you please also test what happens if you apply
- just patch 1
- just patch 2
Thanks!
On Tue, Aug 28, 2012 at 03:35:00PM +0200, Sasha Levin wrote:
quoted
On 08/28/2012 03:20 PM, Michael S. Tsirkin wrote:
quoted
On Tue, Aug 28, 2012 at 03:04:03PM +0200, Sasha Levin wrote:
quoted
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
I imagine this helps performance? Any numbers?
I ran benchmarks on the original RFC, I've re-tested it now and got similar
numbers to the original ones (virtio-net using vhost-net, thresh=16):
Before:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 4512.12
After:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 5399.18
Thanks,
Sasha
This is with both patches 1 + 2?
Sorry could you please also test what happens if you apply
- just patch 1
- just patch 2
Thanks!
Sure thing!
I've also re-ran it on a IBM server type host instead of my laptop. Here are the
results:
Vanilla kernel:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 7922.72
Patch 1, with threshold=16:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8415.07
Patch 2:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8931.05
Note that these are simple tests with netperf listening on one end and a simple
'netperf -H [host]' within the guest. If there are other tests which may be
interesting please let me know.
Thanks,
Sasha
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-08-29 15:13:33
On Wed, Aug 29, 2012 at 05:03:03PM +0200, Sasha Levin wrote:
On 08/29/2012 01:07 PM, Michael S. Tsirkin wrote:
quoted
On Tue, Aug 28, 2012 at 03:35:00PM +0200, Sasha Levin wrote:
quoted
On 08/28/2012 03:20 PM, Michael S. Tsirkin wrote:
quoted
On Tue, Aug 28, 2012 at 03:04:03PM +0200, Sasha Levin wrote:
quoted
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
I imagine this helps performance? Any numbers?
I ran benchmarks on the original RFC, I've re-tested it now and got similar
numbers to the original ones (virtio-net using vhost-net, thresh=16):
Before:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 4512.12
After:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 5399.18
Thanks,
Sasha
This is with both patches 1 + 2?
Sorry could you please also test what happens if you apply
- just patch 1
- just patch 2
Thanks!
Sure thing!
I've also re-ran it on a IBM server type host instead of my laptop. Here are the
results:
Vanilla kernel:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 7922.72
Patch 1, with threshold=16:
OK so let us set it to 16 for virtio-net by default then?
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8415.07
Patch 2:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8931.05
Note that these are simple tests with netperf listening on one end and a simple
'netperf -H [host]' within the guest. If there are other tests which may be
interesting please let me know.
Thanks,
Sasha
Checking that host CPU utilization did not jump would be nice.
E.g. measure BW/host CPU.
--
MST
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-08-29 15:37:04
On Tue, Aug 28, 2012 at 03:04:03PM +0200, Sasha Levin wrote:
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
The API is ugly - how does driver know what to set?
Is this a typical request size? Then let's call it that.
Also this is really per VQ, right?
What is a good default for net? I guess max sg?
@@ -97,6 +100,7 @@ static int probe_common(struct virtio_device *vdev)/* We expect a single virtqueue. */vdev->indirect_thresh=indirect_thresh;+vdev->indirect_alloc_thresh=indirect_alloc_thresh;vq=virtio_find_single_vq(vdev,random_recv_done,"input");if(IS_ERR(vq))returnPTR_ERR(vq);
I am not a purist but this line looks way too long.
Also - no need to check cache creation succeeded?
On failure - disable caching?
Also - let's check that values are sane before passing them on?
They come from user after all.
Also - should not threshold be per VQ? E.g. for -net we do not
need the cache for RX unless in legacy big packet mode.
@@ -55,6 +55,9 @@staticunsignedintindirect_thresh;module_param(indirect_thresh,uint,S_IRUGO);+staticunsignedintindirect_alloc_thresh;+module_param(indirect_alloc_thresh,uint,S_IRUGO);+/* a single mutex to manage channel initialization and attachment */staticDEFINE_MUTEX(virtio_9p_lock);staticDECLARE_WAIT_QUEUE_HEAD(vp_wq);
@@ -505,6 +508,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)/* We expect one virtqueue, for requests. */vdev->indirect_thresh=indirect_thresh;+vdev->indirect_alloc_thresh=indirect_alloc_thresh;+chan->vq=virtio_find_single_vq(vdev,req_done,"requests");if(IS_ERR(chan->vq)){err=PTR_ERR(chan->vq);
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-08-29 15:37:21
On Wed, Aug 29, 2012 at 05:03:03PM +0200, Sasha Levin wrote:
On 08/29/2012 01:07 PM, Michael S. Tsirkin wrote:
quoted
On Tue, Aug 28, 2012 at 03:35:00PM +0200, Sasha Levin wrote:
quoted
On 08/28/2012 03:20 PM, Michael S. Tsirkin wrote:
quoted
On Tue, Aug 28, 2012 at 03:04:03PM +0200, Sasha Levin wrote:
quoted
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
I imagine this helps performance? Any numbers?
I ran benchmarks on the original RFC, I've re-tested it now and got similar
numbers to the original ones (virtio-net using vhost-net, thresh=16):
Before:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 4512.12
After:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 5399.18
Thanks,
Sasha
This is with both patches 1 + 2?
Sorry could you please also test what happens if you apply
- just patch 1
- just patch 2
Thanks!
Sure thing!
I've also re-ran it on a IBM server type host instead of my laptop. Here are the
results:
Vanilla kernel:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 7922.72
Patch 1, with threshold=16:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8415.07
Patch 2:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8931.05
Note that these are simple tests with netperf listening on one end and a simple
'netperf -H [host]' within the guest. If there are other tests which may be
interesting please let me know.
Thanks,
Sasha
On Wed, Aug 29, 2012 at 05:03:03PM +0200, Sasha Levin wrote:
quoted
On 08/29/2012 01:07 PM, Michael S. Tsirkin wrote:
quoted
On Tue, Aug 28, 2012 at 03:35:00PM +0200, Sasha Levin wrote:
quoted
On 08/28/2012 03:20 PM, Michael S. Tsirkin wrote:
quoted
On Tue, Aug 28, 2012 at 03:04:03PM +0200, Sasha Levin wrote:
quoted
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
I imagine this helps performance? Any numbers?
I ran benchmarks on the original RFC, I've re-tested it now and got similar
numbers to the original ones (virtio-net using vhost-net, thresh=16):
Before:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 4512.12
After:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 5399.18
Thanks,
Sasha
This is with both patches 1 + 2?
Sorry could you please also test what happens if you apply
- just patch 1
- just patch 2
Thanks!
Sure thing!
I've also re-ran it on a IBM server type host instead of my laptop. Here are the
results:
Vanilla kernel:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 7922.72
Patch 1, with threshold=16:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8415.07
Patch 2:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8931.05
Note that these are simple tests with netperf listening on one end and a simple
'netperf -H [host]' within the guest. If there are other tests which may be
interesting please let me know.
Thanks,
Sasha
And which parameter did you use for patch 2?
Same as in the first one, 16, the only difference in patch 2 is that we use a
kmemcache, so there's no point in changing the threshold vs patch 1.
Thanks,
Sasha
On Tue, Aug 28, 2012 at 03:04:03PM +0200, Sasha Levin wrote:
quoted
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
The API is ugly - how does driver know what to set?
Is this a typical request size? Then let's call it that.
We've discussed it during the RFC phase, the idea is that we don't know what
would be a good number to use as threshold - which is why I'd like to keep it
disabled as default until it gets more serious tests.
The driver doesn't know what to set, the plan was to make it a dynamic
algorithms which would change it based on current load. Since I can't really do
testing which will provide the correct values for that, the decision was to do
it this way as the first stage and modify it later.
Also this is really per VQ, right?
Right, we keep it per-device at this stage to keep it simple.
What is a good default for net? I guess max sg?
I think that it depends on the workload. I'd say we should keep the default to 0
(disabled) unless we can have a good way to adjust it to the load.
@@ -97,6 +100,7 @@ static int probe_common(struct virtio_device *vdev)/* We expect a single virtqueue. */vdev->indirect_thresh=indirect_thresh;+vdev->indirect_alloc_thresh=indirect_alloc_thresh;vq=virtio_find_single_vq(vdev,random_recv_done,"input");if(IS_ERR(vq))returnPTR_ERR(vq);
I am not a purist but this line looks way too long.
Also - no need to check cache creation succeeded?
On failure - disable caching?
Also - let's check that values are sane before passing them on?
They come from user after all.
will fix these two.
Also - should not threshold be per VQ? E.g. for -net we do not
need the cache for RX unless in legacy big packet mode.
We've discussed it two months ago over IRC (at least thats what I have in my
notes) - the plan was to keep it simple per-device until something more advanced
to deal with the threshold shows up.
Thanks,
Sasha
@@ -55,6 +55,9 @@staticunsignedintindirect_thresh;module_param(indirect_thresh,uint,S_IRUGO);+staticunsignedintindirect_alloc_thresh;+module_param(indirect_alloc_thresh,uint,S_IRUGO);+/* a single mutex to manage channel initialization and attachment */staticDEFINE_MUTEX(virtio_9p_lock);staticDECLARE_WAIT_QUEUE_HEAD(vp_wq);
@@ -505,6 +508,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)/* We expect one virtqueue, for requests. */vdev->indirect_thresh=indirect_thresh;+vdev->indirect_alloc_thresh=indirect_alloc_thresh;+chan->vq=virtio_find_single_vq(vdev,req_done,"requests");if(IS_ERR(chan->vq)){err=PTR_ERR(chan->vq);
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-08-29 18:11:25
On Wed, Aug 29, 2012 at 07:14:01PM +0200, Sasha Levin wrote:
On 08/29/2012 05:38 PM, Michael S. Tsirkin wrote:
quoted
On Tue, Aug 28, 2012 at 03:04:03PM +0200, Sasha Levin wrote:
quoted
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
The API is ugly - how does driver know what to set?
Is this a typical request size? Then let's call it that.
We've discussed it during the RFC phase, the idea is that we don't know what
would be a good number to use as threshold - which is why I'd like to keep it
disabled as default until it gets more serious tests.
The driver doesn't know what to set, the plan was to make it a dynamic
algorithms which would change it based on current load. Since I can't really do
testing which will provide the correct values for that, the decision was to do
it this way as the first stage and modify it later.
quoted
Also this is really per VQ, right?
Right, we keep it per-device at this stage to keep it simple.
quoted
What is a good default for net? I guess max sg?
I think that it depends on the workload. I'd say we should keep the default to 0
(disabled) unless we can have a good way to adjust it to the load.
For *all* drivers?
Then it is mostly useless. No one has the time to tweak module
parameters in real life.
For virtio-net, 16+1 is not too much and ensures we always
use the cache.
If that works better than 0 I would say run with 17.
@@ -97,6 +100,7 @@ static int probe_common(struct virtio_device *vdev)/* We expect a single virtqueue. */vdev->indirect_thresh=indirect_thresh;+vdev->indirect_alloc_thresh=indirect_alloc_thresh;vq=virtio_find_single_vq(vdev,random_recv_done,"input");if(IS_ERR(vq))returnPTR_ERR(vq);
I am not a purist but this line looks way too long.
Also - no need to check cache creation succeeded?
On failure - disable caching?
Also - let's check that values are sane before passing them on?
They come from user after all.
will fix these two.
quoted
Also - should not threshold be per VQ? E.g. for -net we do not
need the cache for RX unless in legacy big packet mode.
We've discussed it two months ago over IRC (at least thats what I have in my
notes) - the plan was to keep it simple per-device until something more advanced
to deal with the threshold shows up.
Thanks,
Sasha
@@ -55,6 +55,9 @@staticunsignedintindirect_thresh;module_param(indirect_thresh,uint,S_IRUGO);+staticunsignedintindirect_alloc_thresh;+module_param(indirect_alloc_thresh,uint,S_IRUGO);+/* a single mutex to manage channel initialization and attachment */staticDEFINE_MUTEX(virtio_9p_lock);staticDECLARE_WAIT_QUEUE_HEAD(vp_wq);
@@ -505,6 +508,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)/* We expect one virtqueue, for requests. */vdev->indirect_thresh=indirect_thresh;+vdev->indirect_alloc_thresh=indirect_alloc_thresh;+chan->vq=virtio_find_single_vq(vdev,req_done,"requests");if(IS_ERR(chan->vq)){err=PTR_ERR(chan->vq);
I think that it depends on the workload. I'd say we should keep the default to 0
(disabled) unless we can have a good way to adjust it to the load.
For *all* drivers?
Then it is mostly useless. No one has the time to tweak module
parameters in real life.
For virtio-net, 16+1 is not too much and ensures we always
use the cache.
If that works better than 0 I would say run with 17.
I was being extra-cautious with leaving it disabled until specifically enabled
because I assumed that this would be one of the first comments I'll get if it
was enabled by default :)
If you're comfortable with setting it to a sane default like 17, I'm perfectly
fine with that as well.
Thanks,
Sasha
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-08-29 22:51:37
On Wed, Aug 29, 2012 at 10:46:19PM +0200, Sasha Levin wrote:
On 08/29/2012 08:12 PM, Michael S. Tsirkin wrote:
quoted
quoted
quoted
quoted
quoted
What is a good default for net? I guess max sg?
I think that it depends on the workload. I'd say we should keep the default to 0
(disabled) unless we can have a good way to adjust it to the load.
For *all* drivers?
Then it is mostly useless. No one has the time to tweak module
parameters in real life.
For virtio-net, 16+1 is not too much and ensures we always
use the cache.
If that works better than 0 I would say run with 17.
I was being extra-cautious with leaving it disabled until specifically enabled
because I assumed that this would be one of the first comments I'll get if it
was enabled by default :)
If you're comfortable with setting it to a sane default like 17, I'm perfectly
fine with that as well.
Thanks,
Sasha
If our testing shows it helps and does not trigger regressions, then
why not? module params are mostly there for developers.
They are not all that helpful to users.
Note that these are simple tests with netperf listening on one end and a simple
'netperf -H [host]' within the guest. If there are other tests which may be
interesting please let me know.
Checking that host CPU utilization did not jump would be nice.
E.g. measure BW/host CPU.
Tested it now, no change in CPU between the original, patch 1 and patch 2.
Thanks,
Sasha
From: Rusty Russell <hidden> Date: 2012-09-06 00:02:14
Sasha Levin [off-list ref] writes:
On 08/28/2012 03:20 PM, Michael S. Tsirkin wrote:
quoted
On Tue, Aug 28, 2012 at 03:04:03PM +0200, Sasha Levin wrote:
quoted
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().
This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.
Signed-off-by: Sasha Levin <redacted>
I imagine this helps performance? Any numbers?
I ran benchmarks on the original RFC, I've re-tested it now and got similar
numbers to the original ones (virtio-net using vhost-net, thresh=16):
Before:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 4512.12
After:
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 5399.18
I have an older patch which adjusts the threshold dynamically, can you
compare? User-adjustable thresholds are statistically never adjusted :(
virtio: use indirect buffers based on demand (heuristic)
virtio_ring uses a ring buffer of descriptors: indirect support allows
a single descriptor to refer to a table of descriptors. This saves
space in the ring, but requires a kmalloc/kfree.
Rather than try to figure out what the right threshold at which to use
indirect buffers, we drop the threshold dynamically when the ring is
under stress.
Note: to stress this, I reduced the ring size to 32 in lguest, and a
1G send reduced the threshold to 9.
Note2: I moved the BUG_ON()s above the indirect test, where they belong
(indirect falls thru on OOM, so the constraints still apply).
Signed-off-by: Rusty Russell <redacted>
---
drivers/virtio/virtio_ring.c | 61 ++++++++++++++++++++++++++++++++++++-------
1 file changed, 52 insertions(+), 9 deletions(-)
@@ -89,6 +89,8 @@ struct vring_virtqueue/* Host supports indirect buffers */boolindirect;+/* Threshold before we go indirect. */+unsignedintindirect_threshold;/* Host publishes avail event idx */boolevent;
@@ -174,6 +176,34 @@ static int vring_add_indirect(struct vrireturnhead;}+staticvoidadjust_threshold(structvring_virtqueue*vq,+unsignedintout,unsignedintin)+{+/* There are really two species of virtqueue, and it matters here.+*Iftherearenooutputparts,it'sa"normally full"receivequeue,+*otherwiseit'sa"normally empty"sendqueue.*/+if(out){+/* Leave threshold unless we're full. */+if(out+in<vq->num_free)+return;+}else{+/* Leave threshold unless we're empty. */+if(vq->num_free!=vq->vring.num)+return;+}++/* Never drop threshold below 1 */+vq->indirect_threshold/=2;+vq->indirect_threshold|=1;++#if 0+printk("%s %s: indirect threshold %u (%u+%u vs %u)\n",+dev_name(&vq->vq.vdev->dev),+vq->vq.name,vq->indirect_threshold,+out,in,vq->num_free);+#endif+}+intvirtqueue_get_queue_index(structvirtqueue*_vq){structvring_virtqueue*vq=to_vvq(_vq);
@@ -226,17 +256,32 @@ int virtqueue_add_buf(struct virtqueue *}#endif-/* If the host supports indirect descriptor tables, and we have multiple-*buffers,thengoindirect.FIXME:tunethisthreshold*/-if(vq->indirect&&(out+in)>1&&vq->num_free){-head=vring_add_indirect(vq,sg,out,in,gfp);-if(likely(head>=0))-gotoadd_head;-}-BUG_ON(out+in>vq->vring.num);BUG_ON(out+in==0);++/* If the host supports indirect descriptor tables, consider it. */+if(vq->indirect){+booltry_indirect;++/* We tweak the threshold automatically. */+adjust_threshold(vq,out,in);++/* If we can't fit any at all, fall through. */+if(vq->num_free==0)+try_indirect=false;+elseif(out+in>vq->num_free)+try_indirect=true;+else+try_indirect=(out+in>vq->indirect_threshold);++if(try_indirect){+head=vring_add_indirect(vq,sg,out,in);+if(head!=vq->vring.num)+gotoadd_head;+}+}+if(vq->num_free<out+in){pr_debug("Can't add buf len %i - avail = %i\n",out+in,vq->num_free);
@@ -666,6 +711,7 @@ struct virtqueue *vring_new_virtqueue(un#endifvq->indirect=virtio_has_feature(vdev,VIRTIO_RING_F_INDIRECT_DESC);+vq->indirect_threshold=num;vq->event=virtio_has_feature(vdev,VIRTIO_RING_F_EVENT_IDX);/* No callback? Tell other side not to bother us. */
From: Rusty Russell <hidden> Date: 2012-09-06 03:01:57
Sasha Levin [off-list ref] writes:
quoted
On Wed, Aug 29, 2012 at 05:03:03PM +0200, Sasha Levin wrote:
quoted
I've also re-ran it on a IBM server type host instead of my laptop. Here are the
results:
Vanilla kernel:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 7922.72
Patch 1, with threshold=16:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8415.07
Patch 2:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8931.05
Note that these are simple tests with netperf listening on one end and a simple
'netperf -H [host]' within the guest. If there are other tests which may be
interesting please let me know.
It might be worth just unconditionally having a cache for the 2
descriptor case. This is what I get with qemu tap, though for some
reason the device features don't have guest or host CSUM, so my setup is
probably screwed:
Queue histogram for virtio0:
Size distribution for input (max=128427):
1: 128427 ################################################################
Size distribution for output (max=256485):
2: 256485 ################################################################
Size distribution for control (max=10):
3: 10 ################################################################
4: 5 ################################
Here's a patch, what do you get (run ifconfig to trigger the dump; yeah,
it's a hack!)
Hack: histogram of buffer sizes for virtio devices.
Currently triggered by a stats query (eg ifconfig) on a net device.
@@ -120,6 +120,8 @@ struct vring_virtqueuektime_tlast_add_time;#endif+unsignedint*histo;+/* Tokens for callbacks. */void*data[];};
@@ -259,6 +261,8 @@ int virtqueue_add_buf(struct virtqueue *BUG_ON(out+in>vq->vring.num);BUG_ON(out+in==0);+vq->histo[out+in]++;+/* If the host supports indirect descriptor tables, consider it. */if(vq->indirect){booltry_indirect;
@@ -772,4 +777,33 @@ unsigned int virtqueue_get_vring_size(st}EXPORT_SYMBOL_GPL(virtqueue_get_vring_size);+voidvirtqueue_dump_histogram(conststructvirtqueue*_vq)+{+conststructvring_virtqueue*vq=to_vvq(_vq);+inti,j,start=0,end=0,max=1;+charline[120];++for(i=0;i<vq->vring.num;i++){+if(!vq->histo[i])+continue;++end=i;+if(!vq->histo[start])+start=i;++if(vq->histo[i]>max)+max=vq->histo[i];+}++printk("Size distribution for %s (max=%u):\n",_vq->name,max);+for(i=start;i<=end;i++){+unsignedintoff;+off=sprintf(line,"%3u: %-7u ",i,vq->histo[i]);+for(j=0;j<vq->histo[i]*64/max;j++)+line[off++]='#';+line[off]='\0';+printk("%s\n",line);+}+}+MODULE_LICENSE("GPL");
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-09-06 05:01:41
On Thu, Sep 06, 2012 at 10:32:48AM +0930, Rusty Russell wrote:
Sasha Levin [off-list ref] writes:
quoted
quoted
On Wed, Aug 29, 2012 at 05:03:03PM +0200, Sasha Levin wrote:
quoted
I've also re-ran it on a IBM server type host instead of my laptop. Here are the
results:
Vanilla kernel:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 7922.72
Patch 1, with threshold=16:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8415.07
Patch 2:
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.33.1
() port 0 AF_INET
enable_enobufs failed: getprotobyname
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8931.05
Note that these are simple tests with netperf listening on one end and a simple
'netperf -H [host]' within the guest. If there are other tests which may be
interesting please let me know.
It might be worth just unconditionally having a cache for the 2
descriptor case. This is what I get with qemu tap, though for some
reason the device features don't have guest or host CSUM, so my setup is
probably screwed:
Yes without checksum net core always linearizes packets, so yes it is
screwed.
For -net, skb always allocates space for 17 frags + linear part so
it seems sane to do same in virtio core, and allocate, for -net,
up to max_frags + 1 from cache.
We can adjust it: no _SG -> 2 otherwise 18.
Not sure about other drivers, maybe really use 2 there for now.
quoted hunk
Queue histogram for virtio0:
Size distribution for input (max=128427):
1: 128427 ################################################################
Size distribution for output (max=256485):
2: 256485 ################################################################
Size distribution for control (max=10):
3: 10 ################################################################
4: 5 ################################
Here's a patch, what do you get (run ifconfig to trigger the dump; yeah,
it's a hack!)
Hack: histogram of buffer sizes for virtio devices.
Currently triggered by a stats query (eg ifconfig) on a net device.
@@ -120,6 +120,8 @@ struct vring_virtqueuektime_tlast_add_time;#endif+unsignedint*histo;+/* Tokens for callbacks. */void*data[];};
@@ -259,6 +261,8 @@ int virtqueue_add_buf(struct virtqueue *BUG_ON(out+in>vq->vring.num);BUG_ON(out+in==0);+vq->histo[out+in]++;+/* If the host supports indirect descriptor tables, consider it. */if(vq->indirect){booltry_indirect;
@@ -772,4 +777,33 @@ unsigned int virtqueue_get_vring_size(st}EXPORT_SYMBOL_GPL(virtqueue_get_vring_size);+voidvirtqueue_dump_histogram(conststructvirtqueue*_vq)+{+conststructvring_virtqueue*vq=to_vvq(_vq);+inti,j,start=0,end=0,max=1;+charline[120];++for(i=0;i<vq->vring.num;i++){+if(!vq->histo[i])+continue;++end=i;+if(!vq->histo[start])+start=i;++if(vq->histo[i]>max)+max=vq->histo[i];+}++printk("Size distribution for %s (max=%u):\n",_vq->name,max);+for(i=start;i<=end;i++){+unsignedintoff;+off=sprintf(line,"%3u: %-7u ",i,vq->histo[i]);+for(j=0;j<vq->histo[i]*64/max;j++)+line[off++]='#';+line[off]='\0';+printk("%s\n",line);+}+}+MODULE_LICENSE("GPL");
From: Rusty Russell <hidden> Date: 2012-09-06 07:57:23
"Michael S. Tsirkin" [off-list ref] writes:
Yes without checksum net core always linearizes packets, so yes it is
screwed.
For -net, skb always allocates space for 17 frags + linear part so
it seems sane to do same in virtio core, and allocate, for -net,
up to max_frags + 1 from cache.
We can adjust it: no _SG -> 2 otherwise 18.
But I thought it used individual buffers these days?
Cheers,
Rusty.
From: Paolo Bonzini <pbonzini@redhat.com> Date: 2012-09-10 15:52:54
Il 06/09/2012 07:02, Michael S. Tsirkin ha scritto:
quoted
quoted
It might be worth just unconditionally having a cache for the 2
descriptor case. This is what I get with qemu tap, though for some
reason the device features don't have guest or host CSUM, so my setup is
probably screwed:
Yes without checksum net core always linearizes packets, so yes it is
screwed.
For -net, skb always allocates space for 17 frags + linear part so
it seems sane to do same in virtio core, and allocate, for -net,
up to max_frags + 1 from cache.
We can adjust it: no _SG -> 2 otherwise 18.
Not sure about other drivers, maybe really use 2 there for now.
2 should also be good for virtio-blk and virtio-scsi 4KB random rw
workloads.
Paolo