diff mbox

[5/5] qemu-img bench: Add --flush-interval

Message ID 1464957021-3469-6-git-send-email-kwolf@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Kevin Wolf June 3, 2016, 12:30 p.m. UTC
This options allows to flush the image periodically during write tests.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qemu-img-cmds.hx |  4 ++--
 qemu-img.c       | 69 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 qemu-img.texi    |  6 ++++-
 3 files changed, 67 insertions(+), 12 deletions(-)

Comments

Denis V. Lunev June 3, 2016, 3:01 p.m. UTC | #1
On 06/03/2016 03:30 PM, Kevin Wolf wrote:
> This options allows to flush the image periodically during write tests.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This pattern could be a bit different - you wait requests to finish
and after that start flush. In this case there is no gain with my
patch ;)

You should treat flush as ordinary write request i.e. place
request immediately without waiting for writes to finish.
May be this could be specified as an operation mode.

Den
Kevin Wolf June 3, 2016, 3:16 p.m. UTC | #2
Am 03.06.2016 um 17:01 hat Denis V. Lunev geschrieben:
> On 06/03/2016 03:30 PM, Kevin Wolf wrote:
> >This options allows to flush the image periodically during write tests.
> >
> >Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> This pattern could be a bit different - you wait requests to finish
> and after that start flush. In this case there is no gain with my
> patch ;)
> 
> You should treat flush as ordinary write request i.e. place
> request immediately without waiting for writes to finish.
> May be this could be specified as an operation mode.

Hm, okay, I can try that.

What OS is running on your guest? Because I seem to remember that Linux
drains the queue before sending a flush command. This is why I
implemented it this way here. Maybe it changed in Linux, though.

Kevin
Kevin Wolf June 6, 2016, 12:33 p.m. UTC | #3
Am 03.06.2016 um 17:16 hat Kevin Wolf geschrieben:
> Am 03.06.2016 um 17:01 hat Denis V. Lunev geschrieben:
> > On 06/03/2016 03:30 PM, Kevin Wolf wrote:
> > >This options allows to flush the image periodically during write tests.
> > >
> > >Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > This pattern could be a bit different - you wait requests to finish
> > and after that start flush. In this case there is no gain with my
> > patch ;)
> > 
> > You should treat flush as ordinary write request i.e. place
> > request immediately without waiting for writes to finish.
> > May be this could be specified as an operation mode.
> 
> Hm, okay, I can try that.

Doesn't make a difference for me. But I'll include the option in v2
anyway.

Kevin
diff mbox

Patch

diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index f5d0098..04d70d4 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -10,9 +10,9 @@  STEXI
 ETEXI
 
 DEF("bench", img_bench,
-    "bench [-c count] [-d depth] [-f fmt] [-n] [-o offset] [-q] [-s buffer_size] [-S step_size] [-t cache] [-w] filename")
+    "bench [-c count] [-d depth] [-f fmt] [--flush-interval=flush_interval] [-n] [-o offset] [-q] [-s buffer_size] [-S step_size] [-t cache] [-w] filename")
 STEXI
-@item bench [-c @var{count}] [-d @var{depth}] [-f @var{fmt}] [-n] [-o @var{offset}] [-q] [-s @var{buffer_size}] [-S @var{step_size}] [-t @var{cache}] [-w] @var{filename}
+@item bench [-c @var{count}] [-d @var{depth}] [-f @var{fmt}] [--flush-interval=@var{flush_interval}] [-n] [-o @var{offset}] [-q] [-s @var{buffer_size}] [-S @var{step_size}] [-t @var{cache}] [-w] @var{filename}
 ETEXI
 
 DEF("check", img_check,
diff --git a/qemu-img.c b/qemu-img.c
index ff99181..76904db 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -53,6 +53,7 @@  enum {
     OPTION_BACKING_CHAIN = 257,
     OPTION_OBJECT = 258,
     OPTION_IMAGE_OPTS = 259,
+    OPTION_FLUSH_INTERVAL = 260,
 };
 
 typedef enum OutputFormat {
@@ -3467,10 +3468,12 @@  typedef struct BenchData {
     int step;
     int nrreq;
     int n;
+    int flush_interval;
     uint8_t *buf;
     QEMUIOVector *qiov;
 
     int in_flight;
+    bool in_flush;
     uint64_t offset;
 } BenchData;
 
@@ -3483,9 +3486,29 @@  static void bench_cb(void *opaque, int ret)
         error_report("Failed request: %s\n", strerror(-ret));
         exit(EXIT_FAILURE);
     }
-    if (b->in_flight > 0) {
+
+    if (b->in_flush) {
+        /* Just finished a flush: Start next requests */
+        assert(b->in_flight == 0);
+        b->in_flush = false;
+    } else if (b->in_flight > 0) {
+        int remaining = b->n - b->in_flight;
+
         b->n--;
         b->in_flight--;
+
+        /* Time for flush? Drain queue, then flush */
+        if (b->flush_interval && remaining % b->flush_interval == 0) {
+            if (!b->in_flight) {
+                acb = blk_aio_flush(b->blk, bench_cb, b);
+                if (!acb) {
+                    error_report("Failed to issue flush request");
+                    exit(EXIT_FAILURE);
+                }
+                b->in_flush = true;
+            }
+            return;
+        }
     }
 
     while (b->n > b->in_flight && b->in_flight < b->nrreq) {
@@ -3518,6 +3541,7 @@  static int img_bench(int argc, char **argv)
     int64_t offset = 0;
     size_t bufsize = 4096;
     size_t step = 0;
+    int flush_interval = 0;
     int64_t image_size;
     BlockBackend *blk = NULL;
     BenchData data = {};
@@ -3529,6 +3553,7 @@  static int img_bench(int argc, char **argv)
     for (;;) {
         static const struct option long_options[] = {
             {"help", no_argument, 0, 'h'},
+            {"flush-interval", required_argument, 0, OPTION_FLUSH_INTERVAL},
             {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {0, 0, 0, 0}
         };
@@ -3626,6 +3651,17 @@  static int img_bench(int argc, char **argv)
             flags |= BDRV_O_RDWR;
             is_write = true;
             break;
+        case OPTION_FLUSH_INTERVAL:
+        {
+            char *end;
+            errno = 0;
+            flush_interval = strtoul(optarg, &end, 0);
+            if (errno || *end || flush_interval > INT_MAX) {
+                error_report("Invalid flush interval specified");
+                return 1;
+            }
+            break;
+        }
         case OPTION_IMAGE_OPTS:
             image_opts = true;
             break;
@@ -3637,6 +3673,17 @@  static int img_bench(int argc, char **argv)
     }
     filename = argv[argc - 1];
 
+    if (!is_write && flush_interval) {
+        error_report("--flush-interval is only available in write tests");
+        ret = -1;
+        goto out;
+    }
+    if (flush_interval && flush_interval < depth) {
+        error_report("Flush interval can't be smaller than depth");
+        ret = -1;
+        goto out;
+    }
+
     blk = img_open(image_opts, filename, fmt, flags, writethrough, quiet);
     if (!blk) {
         ret = -1;
@@ -3650,19 +3697,23 @@  static int img_bench(int argc, char **argv)
     }
 
     data = (BenchData) {
-        .blk        = blk,
-        .image_size = image_size,
-        .bufsize    = bufsize,
-        .step       = step ?: bufsize,
-        .nrreq      = depth,
-        .n          = count,
-        .offset     = offset,
-        .write      = is_write,
+        .blk            = blk,
+        .image_size     = image_size,
+        .bufsize        = bufsize,
+        .step           = step ?: bufsize,
+        .nrreq          = depth,
+        .n              = count,
+        .offset         = offset,
+        .write          = is_write,
+        .flush_interval = flush_interval,
     };
     printf("Sending %d %s requests, %d bytes each, %d in parallel "
            "(starting at offset %" PRId64 ", step size %d)\n",
            data.n, data.write ? "write" : "read", data.bufsize, data.nrreq,
            data.offset, data.step);
+    if (flush_interval) {
+        printf("Sending flush every %d requests\n", flush_interval);
+    }
 
     data.buf = blk_blockalign(blk, data.nrreq * data.bufsize);
     memset(data.buf, 0, data.nrreq * data.bufsize);
diff --git a/qemu-img.texi b/qemu-img.texi
index 6b03d3f..270fb4c 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -131,7 +131,7 @@  Skip the creation of the target volume
 Command description:
 
 @table @option
-@item bench [-c @var{count}] [-d @var{depth}] [-f @var{fmt}] [-n] [-o @var{offset}] [-q] [-s @var{buffer_size}] [-S @var{step_size}] [-t @var{cache}] [-w] @var{filename}
+@item bench [-c @var{count}] [-d @var{depth}] [-f @var{fmt}] [--flush-interval=@var{flush_interval}] [-n] [-o @var{offset}] [-q] [-s @var{buffer_size}] [-S @var{step_size}] [-t @var{cache}] [-w] @var{filename}
 
 Run a simple sequential I/O benchmark on the specified image. If @code{-w} is
 specified, a write test is performed, otherwise a read test is performed.
@@ -142,6 +142,10 @@  starts at the position given by @var{offset}, each following request increases
 the current position by @var{step_size}. If @var{step_size} is not given,
 @var{buffer_size} is used for its value.
 
+If @var{flush_interval} is specified for a write test, the queue is drained and
+a flush is issued before new writes are made whenever the number of remaining
+requests is a multiple of @var{flush_interval}.
+
 If @code{-n} is specified, the native AIO backend is used if possible. On
 Linux, this option only works if @code{-t none} or @code{-t directsync} is
 specified as well.