2022-07-09 02:36:00

by Guo Zhi

[permalink] [raw]
Subject: [PATCH v3 0/4] virtio/virtio_test

Original virtio_test only use add one descriptor for each io event, thus code of descriptor chain and indirection have not been tested(one descriptor will not use indirect feature even indirect feature has been specified). In fact it would have not been possible for vhost_test to access to the indirect descriptor table, because it's impossible for virtio_ring.c to allocate it.

This series using descriptor chain and enable indirection feature. And through gcov we find the code coverage has been improved(not high for virtio_ring.c because virtio_test only test split virtqueue):

+------------+-------------+-------------+
| |virtio_test.c|virtio_ring.c|
+------------+-------------+-------------+
| original | 72.32% | 24.71% |
+------------+-------------+-------------+
| current | 75% | 28.05% |
+------------+-------------+-------------+

Guo Zhi (4):
virtio_test: kick vhost for a batch of descriptors
virtio_test: use random length scatterlists to test descriptor chain
virtio_test: enable indirection feature
virtio_test: pregenerate random numbers

tools/virtio/virtio_test.c | 85 ++++++++++++++++++++++++++++++--------
1 file changed, 68 insertions(+), 17 deletions(-)

--
2.17.1


2022-07-09 02:36:08

by Guo Zhi

[permalink] [raw]
Subject: [PATCH v3 1/4] virtio_test: kick vhost for a batch of descriptors

Only kick vhost when the batch finishes.

Signed-off-by: Guo Zhi <[email protected]>
---
tools/virtio/virtio_test.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index 23f142af5..95f78b311 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -208,11 +208,10 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
}

++started;
-
- if (unlikely(!virtqueue_kick(vq->vq))) {
- r = -1;
- break;
- }
+ }
+ if (unlikely(!virtqueue_kick(vq->vq))) {
+ r = -1;
+ break;
}

if (started >= bufs)
--
2.17.1

2022-07-09 02:36:26

by Guo Zhi

[permalink] [raw]
Subject: [PATCH v3 3/4] virtio_test: enable indirection feature

Prior implementation don't use indirection feature because there is only
one descriptor for every io event, actually prior implementation don't
support indirection because vhost can't translate and find the indirect
descriptors. This commit enable virtio_test malloc indirect descriptors
in a indirect buffer and map this buffer to vhost, thus resolve this
problem.

Signed-off-by: Guo Zhi <[email protected]>
---
v3:
- use C style comment
- changed INDIRECT_TABLE name
- add comment for __kmalloc_fake
---
tools/virtio/virtio_test.c | 56 ++++++++++++++++++++++++++++++++------
1 file changed, 47 insertions(+), 9 deletions(-)

diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index 1408a4a20..8f3ef3a78 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -21,8 +21,9 @@

#define RANDOM_BATCH -1
#define MAX_SG_FRAGS 8UL
+#define RINGSIZE 256
+#define INDIRECT_TABLE_SIZE (RINGSIZE * sizeof(struct vring_desc) * 8)

-/* Unused */
void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;

struct vq_info {
@@ -44,6 +45,8 @@ struct vdev_info {
int nvqs;
void *buf;
size_t buf_size;
+ void *indirect_table;
+ size_t indirect_table_size;
struct vhost_memory *mem;
};

@@ -128,6 +131,8 @@ static void vq_info_add(struct vdev_info *dev, int num)
static void vdev_info_init(struct vdev_info* dev, unsigned long long features)
{
int r;
+ int nregions = 2;
+
memset(dev, 0, sizeof *dev);
dev->vdev.features = features;
INIT_LIST_HEAD(&dev->vdev.vqs);
@@ -135,19 +140,25 @@ static void vdev_info_init(struct vdev_info* dev, unsigned long long features)
dev->buf_size = 1024;
dev->buf = malloc(dev->buf_size);
assert(dev->buf);
- dev->control = open("/dev/vhost-test", O_RDWR);
+ dev->indirect_table_size = INDIRECT_TABLE_SIZE;
+ dev->indirect_table = malloc(dev->indirect_table_size);
+ assert(dev->indirect_table);
+ dev->control = open("/dev/vhost-test", O_RDWR);
assert(dev->control >= 0);
r = ioctl(dev->control, VHOST_SET_OWNER, NULL);
assert(r >= 0);
dev->mem = malloc(offsetof(struct vhost_memory, regions) +
- sizeof dev->mem->regions[0]);
+ (sizeof(dev->mem->regions[0])) * nregions);
assert(dev->mem);
memset(dev->mem, 0, offsetof(struct vhost_memory, regions) +
- sizeof dev->mem->regions[0]);
- dev->mem->nregions = 1;
+ (sizeof(dev->mem->regions[0])) * nregions);
+ dev->mem->nregions = nregions;
dev->mem->regions[0].guest_phys_addr = (long)dev->buf;
dev->mem->regions[0].userspace_addr = (long)dev->buf;
dev->mem->regions[0].memory_size = dev->buf_size;
+ dev->mem->regions[1].guest_phys_addr = (long)dev->indirect_table;
+ dev->mem->regions[1].userspace_addr = (long)dev->indirect_table;
+ dev->mem->regions[1].memory_size = dev->indirect_table_size;
r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
assert(r >= 0);
}
@@ -167,6 +178,22 @@ static void wait_for_interrupt(struct vdev_info *dev)
}
}

+static int test_virtqueue_add_outbuf(struct virtqueue *vq,
+ struct scatterlist *sg, unsigned int num,
+ void *data, void *indirect_table)
+{
+ int r;
+
+ /* Allocate an indirect, force it to allocate user addr
+ * exists in vhost iotlb, otherwise vhost can't access
+ */
+ __kmalloc_fake = indirect_table;
+ r = virtqueue_add_outbuf(vq, sg, num, data,
+ GFP_ATOMIC);
+ __kmalloc_fake = NULL;
+ return r;
+}
+
static void run_test(struct vdev_info *dev, struct vq_info *vq,
bool delayed, int batch, int reset_n, int bufs)
{
@@ -178,6 +205,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
unsigned len;
long long spurious = 0;
const bool random_batch = batch == RANDOM_BATCH;
+ void *indirect_table;

r = ioctl(dev->control, VHOST_TEST_RUN, &test);
assert(r >= 0);
@@ -185,10 +213,15 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
next_reset = INT_MAX;
}

+ /* Don't kfree indirect_table. */
+ __kfree_ignore_start = dev->indirect_table;
+ __kfree_ignore_end = dev->indirect_table + dev->indirect_table_size;
+
for (;;) {
virtqueue_disable_cb(vq->vq);
completed_before = completed;
started_before = started;
+ indirect_table = dev->indirect_table;
do {
const bool reset = completed > next_reset;
if (random_batch)
@@ -200,9 +233,13 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
sg_init_table(sg, sg_size);
for (int i = 0; i < sg_size; ++i)
sg_set_buf(&sg[i], dev->buf + i, 0x1);
- r = virtqueue_add_outbuf(vq->vq, sg, sg_size,
- dev->buf + started,
- GFP_ATOMIC);
+
+ /* use indirect_table buffer repeatedly */
+ if (indirect_table + sg_size * sizeof(struct vring_desc) >
+ dev->indirect_table + dev->indirect_table_size)
+ indirect_table = dev->indirect_table;
+ r = test_virtqueue_add_outbuf(vq->vq, sg, sg_size,
+ dev->buf + started, indirect_table);
if (unlikely(r != 0)) {
if (r == -ENOSPC &&
started > started_before)
@@ -213,6 +250,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
}

++started;
+ indirect_table += sg_size * sizeof(struct vring_desc);
}
if (unlikely(!virtqueue_kick(vq->vq))) {
r = -1;
@@ -401,7 +439,7 @@ int main(int argc, char **argv)

done:
vdev_info_init(&dev, features);
- vq_info_add(&dev, 256);
+ vq_info_add(&dev, RINGSIZE);
run_test(&dev, &dev.vqs[0], delayed, batch, reset, 0x100000);
return 0;
}
--
2.17.1

2022-07-09 02:36:58

by Guo Zhi

[permalink] [raw]
Subject: [PATCH v3 4/4] virtio_test: pregenerate random numbers

random numbers on data path is expensive, using a rand pool to
pregenerate them before tests start

Signed-off-by: Guo Zhi <[email protected]>
---
tools/virtio/virtio_test.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index 8f3ef3a78..7cc43e5bf 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -23,6 +23,7 @@
#define MAX_SG_FRAGS 8UL
#define RINGSIZE 256
#define INDIRECT_TABLE_SIZE (RINGSIZE * sizeof(struct vring_desc) * 8)
+#define RAND_POOL_SIZE 4096

void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;

@@ -199,6 +200,8 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
{
struct scatterlist sg[MAX_SG_FRAGS];
int sg_size = 0;
+ int rand_pool[RAND_POOL_SIZE];
+ unsigned int rand_idx;
long started = 0, completed = 0, next_reset = reset_n;
long completed_before, started_before;
int r, test = 1;
@@ -213,6 +216,10 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
next_reset = INT_MAX;
}

+ /* Init rand pool */
+ for (rand_idx = 0; rand_idx < RAND_POOL_SIZE; ++rand_idx)
+ rand_pool[rand_idx] = random();
+
/* Don't kfree indirect_table. */
__kfree_ignore_start = dev->indirect_table;
__kfree_ignore_end = dev->indirect_table + dev->indirect_table_size;
@@ -225,11 +232,13 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
do {
const bool reset = completed > next_reset;
if (random_batch)
- batch = (random() % vq->vring.num) + 1;
+ batch = (rand_pool[rand_idx++ % RAND_POOL_SIZE]
+ % vq->vring.num) + 1;

while (started < bufs &&
(started - completed) < batch) {
- sg_size = random() % (MAX_SG_FRAGS - 1) + 1;
+ sg_size = (rand_pool[rand_idx++ % RAND_POOL_SIZE]
+ % (MAX_SG_FRAGS - 1)) + 1;
sg_init_table(sg, sg_size);
for (int i = 0; i < sg_size; ++i)
sg_set_buf(&sg[i], dev->buf + i, 0x1);
--
2.17.1

2022-07-09 02:55:14

by Guo Zhi

[permalink] [raw]
Subject: [PATCH v3 2/4] virtio_test: use random length scatterlists to test descriptor chain

Prior implementation only use one descriptor for each io event, which
does't test code of descriptor chain. More importantly, one descriptor
will not use indirect feature even indirect feature is specified. Use
random length scatterlists here to test descriptor chain.

Signed-off-by: Guo Zhi <[email protected]>
---
v3:
- drop fda270fcd virtio_test: move magic number in code as defined constant
---
tools/virtio/virtio_test.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index 95f78b311..1408a4a20 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -20,6 +20,7 @@
#include "../../drivers/vhost/test.h"

#define RANDOM_BATCH -1
+#define MAX_SG_FRAGS 8UL

/* Unused */
void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;
@@ -169,7 +170,8 @@ static void wait_for_interrupt(struct vdev_info *dev)
static void run_test(struct vdev_info *dev, struct vq_info *vq,
bool delayed, int batch, int reset_n, int bufs)
{
- struct scatterlist sl;
+ struct scatterlist sg[MAX_SG_FRAGS];
+ int sg_size = 0;
long started = 0, completed = 0, next_reset = reset_n;
long completed_before, started_before;
int r, test = 1;
@@ -194,8 +196,11 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,

while (started < bufs &&
(started - completed) < batch) {
- sg_init_one(&sl, dev->buf, dev->buf_size);
- r = virtqueue_add_outbuf(vq->vq, &sl, 1,
+ sg_size = random() % (MAX_SG_FRAGS - 1) + 1;
+ sg_init_table(sg, sg_size);
+ for (int i = 0; i < sg_size; ++i)
+ sg_set_buf(&sg[i], dev->buf + i, 0x1);
+ r = virtqueue_add_outbuf(vq->vq, sg, sg_size,
dev->buf + started,
GFP_ATOMIC);
if (unlikely(r != 0)) {
--
2.17.1

2022-07-11 15:48:00

by Eugenio Perez Martin

[permalink] [raw]
Subject: Re: [PATCH v3 2/4] virtio_test: use random length scatterlists to test descriptor chain

On Sat, Jul 9, 2022 at 4:28 AM Guo Zhi <[email protected]> wrote:
>
> Prior implementation only use one descriptor for each io event, which
> does't test code of descriptor chain. More importantly, one descriptor
> will not use indirect feature even indirect feature is specified. Use
> random length scatterlists here to test descriptor chain.
>
> Signed-off-by: Guo Zhi <[email protected]>
> ---
> v3:
> - drop fda270fcd virtio_test: move magic number in code as defined constant
> ---
> tools/virtio/virtio_test.c | 11 ++++++++---
> 1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
> index 95f78b311..1408a4a20 100644
> --- a/tools/virtio/virtio_test.c
> +++ b/tools/virtio/virtio_test.c
> @@ -20,6 +20,7 @@
> #include "../../drivers/vhost/test.h"
>
> #define RANDOM_BATCH -1
> +#define MAX_SG_FRAGS 8UL
>
> /* Unused */
> void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;
> @@ -169,7 +170,8 @@ static void wait_for_interrupt(struct vdev_info *dev)
> static void run_test(struct vdev_info *dev, struct vq_info *vq,
> bool delayed, int batch, int reset_n, int bufs)
> {
> - struct scatterlist sl;
> + struct scatterlist sg[MAX_SG_FRAGS];
> + int sg_size = 0;
> long started = 0, completed = 0, next_reset = reset_n;
> long completed_before, started_before;
> int r, test = 1;
> @@ -194,8 +196,11 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
>
> while (started < bufs &&
> (started - completed) < batch) {
> - sg_init_one(&sl, dev->buf, dev->buf_size);
> - r = virtqueue_add_outbuf(vq->vq, &sl, 1,
> + sg_size = random() % (MAX_SG_FRAGS - 1) + 1;

I'm wondering if it would be simpler to reuse batch randomness here,
and make sg_size = MIN(started - completed, MAX_SG_FRAGS). Vhost test
should go faster because the longer chains, and I guess we should hit
a good range of chain lengths with the batch tail anyway.

Thanks!

> + sg_init_table(sg, sg_size);
> + for (int i = 0; i < sg_size; ++i)
> + sg_set_buf(&sg[i], dev->buf + i, 0x1);
> + r = virtqueue_add_outbuf(vq->vq, sg, sg_size,
> dev->buf + started,
> GFP_ATOMIC);
> if (unlikely(r != 0)) {
> --
> 2.17.1
>

2022-07-17 12:07:18

by Guo Zhi

[permalink] [raw]
Subject: Re: [PATCH v3 2/4] virtio_test: use random length scatterlists to test descriptor chain

On 2022/7/11 23:35, Eugenio Perez Martin wrote:
> On Sat, Jul 9, 2022 at 4:28 AM Guo Zhi <[email protected]> wrote:
>> Prior implementation only use one descriptor for each io event, which
>> does't test code of descriptor chain. More importantly, one descriptor
>> will not use indirect feature even indirect feature is specified. Use
>> random length scatterlists here to test descriptor chain.
>>
>> Signed-off-by: Guo Zhi <[email protected]>
>> ---
>> v3:
>> - drop fda270fcd virtio_test: move magic number in code as defined constant
>> ---
>> tools/virtio/virtio_test.c | 11 ++++++++---
>> 1 file changed, 8 insertions(+), 3 deletions(-)
>>
>> diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
>> index 95f78b311..1408a4a20 100644
>> --- a/tools/virtio/virtio_test.c
>> +++ b/tools/virtio/virtio_test.c
>> @@ -20,6 +20,7 @@
>> #include "../../drivers/vhost/test.h"
>>
>> #define RANDOM_BATCH -1
>> +#define MAX_SG_FRAGS 8UL
>>
>> /* Unused */
>> void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;
>> @@ -169,7 +170,8 @@ static void wait_for_interrupt(struct vdev_info *dev)
>> static void run_test(struct vdev_info *dev, struct vq_info *vq,
>> bool delayed, int batch, int reset_n, int bufs)
>> {
>> - struct scatterlist sl;
>> + struct scatterlist sg[MAX_SG_FRAGS];
>> + int sg_size = 0;
>> long started = 0, completed = 0, next_reset = reset_n;
>> long completed_before, started_before;
>> int r, test = 1;
>> @@ -194,8 +196,11 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
>>
>> while (started < bufs &&
>> (started - completed) < batch) {
>> - sg_init_one(&sl, dev->buf, dev->buf_size);
>> - r = virtqueue_add_outbuf(vq->vq, &sl, 1,
>> + sg_size = random() % (MAX_SG_FRAGS - 1) + 1;
> I'm wondering if it would be simpler to reuse batch randomness here,
> and make sg_size = MIN(started - completed, MAX_SG_FRAGS). Vhost test
> should go faster because the longer chains, and I guess we should hit
> a good range of chain lengths with the batch tail anyway.
>
> Thanks!

IMHO, if we reuse batch randomness here, the random length of
scatterlist only appears when --batch=random selected.

Otherwise, when we have to specify the batch size(eg, 256), the
scatterlist( as well as the descriptor chain len) will not be randomed.
So I propose decouple the randomness of batch size and descriptor chain
length.

If we have to achive better performance for vhost_test, just enlarge the
MAX_SG_FRAGS is ok.

>> + sg_init_table(sg, sg_size);
>> + for (int i = 0; i < sg_size; ++i)
>> + sg_set_buf(&sg[i], dev->buf + i, 0x1);
>> + r = virtqueue_add_outbuf(vq->vq, sg, sg_size,
>> dev->buf + started,
>> GFP_ATOMIC);
>> if (unlikely(r != 0)) {
>> --
>> 2.17.1
>>

2022-07-21 11:59:23

by Guo Zhi

[permalink] [raw]
Subject: Re: [PATCH v3 0/4] virtio/virtio_test

On 2022/7/9 10:27, Guo Zhi wrote:
> Original virtio_test only use add one descriptor for each io event, thus code of descriptor chain and indirection have not been tested(one descriptor will not use indirect feature even indirect feature has been specified). In fact it would have not been possible for vhost_test to access to the indirect descriptor table, because it's impossible for virtio_ring.c to allocate it.
>
> This series using descriptor chain and enable indirection feature. And through gcov we find the code coverage has been improved(not high for virtio_ring.c because virtio_test only test split virtqueue):
>
> +------------+-------------+-------------+
> | |virtio_test.c|virtio_ring.c|
> +------------+-------------+-------------+
> | original | 72.32% | 24.71% |
> +------------+-------------+-------------+
> | current | 75% | 28.05% |
> +------------+-------------+-------------+
>
> Guo Zhi (4):
> virtio_test: kick vhost for a batch of descriptors
> virtio_test: use random length scatterlists to test descriptor chain
> virtio_test: enable indirection feature
> virtio_test: pregenerate random numbers
>
> tools/virtio/virtio_test.c | 85 ++++++++++++++++++++++++++++++--------
> 1 file changed, 68 insertions(+), 17 deletions(-)
>
Hi, the new version patch of virtio_test is waiting for review:)

Thanks.

2022-08-03 09:24:53

by Guo Zhi

[permalink] [raw]
Subject: Re: [PATCH v3 0/4] virtio/virtio_test



----- Original Message -----
> From: "Guo Zhi" <[email protected]>
> To: "jasowang" <[email protected]>, "Michael Tsirkin" <[email protected]>
> Cc: "eperezma" <[email protected]>, "virtualization" <[email protected]>, "linux-kernel"
> <[email protected]>, "sgarzare" <[email protected]>
> Sent: Thursday, July 21, 2022 7:55:31 PM
> Subject: Re: [PATCH v3 0/4] virtio/virtio_test

> On 2022/7/9 10:27, Guo Zhi wrote:
>> Original virtio_test only use add one descriptor for each io event, thus code of
>> descriptor chain and indirection have not been tested(one descriptor will not
>> use indirect feature even indirect feature has been specified). In fact it
>> would have not been possible for vhost_test to access to the indirect
>> descriptor table, because it's impossible for virtio_ring.c to allocate it.
>>
>> This series using descriptor chain and enable indirection feature. And through
>> gcov we find the code coverage has been improved(not high for virtio_ring.c
>> because virtio_test only test split virtqueue):
>>
>> +------------+-------------+-------------+
>> | |virtio_test.c|virtio_ring.c|
>> +------------+-------------+-------------+
>> | original | 72.32% | 24.71% |
>> +------------+-------------+-------------+
>> | current | 75% | 28.05% |
>> +------------+-------------+-------------+
>>
>> Guo Zhi (4):
>> virtio_test: kick vhost for a batch of descriptors
>> virtio_test: use random length scatterlists to test descriptor chain
>> virtio_test: enable indirection feature
>> virtio_test: pregenerate random numbers
>>
>> tools/virtio/virtio_test.c | 85 ++++++++++++++++++++++++++++++--------
>> 1 file changed, 68 insertions(+), 17 deletions(-)
>>
> Hi, the new version patch of virtio_test is waiting for review:)
>
> Thanks.

Friendly ping for the patches:)
Thanks