qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: qemu-devel@nongnu.org
Cc: "Kevin Wolf" <kwolf@redhat.com>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"open list:Block layer core" <qemu-block@nongnu.org>,
	"Max Reitz" <mreitz@redhat.com>
Subject: [Qemu-devel] [PATCH v1 02/26] qemu-io-cmds: use clock_gettime for benchmarking
Date: Thu, 30 May 2019 11:15:39 +0100	[thread overview]
Message-ID: <20190530101603.22254-3-alex.bennee@linaro.org> (raw)
In-Reply-To: <20190530101603.22254-1-alex.bennee@linaro.org>

The previous use of gettimeofday() ran into undefined behaviour when
we ended up doing a div 0 for a very short operation. This is because
gettimeofday only works at the microsecond level as well as being
prone to discontinuous jumps in system time. Using clock_gettime with
CLOCK_MONOTONIC gives greater precision and alleviates some of the
potential problems with time jumping around.

We could use CLOCK_MONOTONIC_RAW to avoid being tripped up by NTP and
adjtime but that is Linux specific so I decided it would do for now.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 qemu-io-cmds.c | 69 +++++++++++++++++++++++++-------------------------
 1 file changed, 35 insertions(+), 34 deletions(-)

diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 30a7d9a13bf..f6701e3b8a8 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -248,20 +248,21 @@ static void cvtstr(double value, char *str, size_t size)
 
 
 
-static struct timeval tsub(struct timeval t1, struct timeval t2)
+static struct timespec tsub(struct timespec t1, struct timespec t2)
 {
-    t1.tv_usec -= t2.tv_usec;
-    if (t1.tv_usec < 0) {
-        t1.tv_usec += 1000000;
+    t1.tv_nsec -= t2.tv_nsec;
+    if (t1.tv_nsec < 0) {
+        t1.tv_nsec += 1000000000;
         t1.tv_sec--;
     }
     t1.tv_sec -= t2.tv_sec;
     return t1;
 }
 
-static double tdiv(double value, struct timeval tv)
+static double tdiv(double value, struct timespec tv)
 {
-    return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
+    double time = (double)tv.tv_sec + ((double)tv.tv_nsec / 1000000000.0);
+    return value / time;
 }
 
 #define HOURS(sec)      ((sec) / (60 * 60))
@@ -274,16 +275,16 @@ enum {
     VERBOSE_FIXED_TIME  = 0x2,
 };
 
-static void timestr(struct timeval *tv, char *ts, size_t size, int format)
+static void timestr(struct timespec *tv, char *ts, size_t size, int format)
 {
-    double usec = (double)tv->tv_usec / 1000000.0;
+    double nsec = (double)tv->tv_nsec / 1000000000.0;
 
     if (format & TERSE_FIXED_TIME) {
         if (!HOURS(tv->tv_sec)) {
             snprintf(ts, size, "%u:%02u.%02u",
                     (unsigned int) MINUTES(tv->tv_sec),
                     (unsigned int) SECONDS(tv->tv_sec),
-                    (unsigned int) (usec * 100));
+                    (unsigned int) (nsec * 100000));
             return;
         }
         format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
@@ -294,9 +295,9 @@ static void timestr(struct timeval *tv, char *ts, size_t size, int format)
                 (unsigned int) HOURS(tv->tv_sec),
                 (unsigned int) MINUTES(tv->tv_sec),
                 (unsigned int) SECONDS(tv->tv_sec),
-                (unsigned int) (usec * 100));
+                (unsigned int) (nsec * 100000));
     } else {
-        snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
+        snprintf(ts, size, "0.%04u sec", (unsigned int) (nsec * 10000000));
     }
 }
 
@@ -376,7 +377,7 @@ static void dump_buffer(const void *buffer, int64_t offset, int64_t len)
     }
 }
 
-static void print_report(const char *op, struct timeval *t, int64_t offset,
+static void print_report(const char *op, struct timespec *t, int64_t offset,
                          int64_t count, int64_t total, int cnt, bool Cflag)
 {
     char s1[64], s2[64], ts[64];
@@ -649,7 +650,7 @@ static const cmdinfo_t read_cmd = {
 
 static int read_f(BlockBackend *blk, int argc, char **argv)
 {
-    struct timeval t1, t2;
+    struct timespec t1, t2;
     bool Cflag = false, qflag = false, vflag = false;
     bool Pflag = false, sflag = false, lflag = false, bflag = false;
     int c, cnt, ret;
@@ -758,13 +759,13 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
 
     buf = qemu_io_alloc(blk, count, 0xab);
 
-    gettimeofday(&t1, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t1);
     if (bflag) {
         ret = do_load_vmstate(blk, buf, offset, count, &total);
     } else {
         ret = do_pread(blk, buf, offset, count, &total);
     }
-    gettimeofday(&t2, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t2);
 
     if (ret < 0) {
         printf("read failed: %s\n", strerror(-ret));
@@ -836,7 +837,7 @@ static const cmdinfo_t readv_cmd = {
 
 static int readv_f(BlockBackend *blk, int argc, char **argv)
 {
-    struct timeval t1, t2;
+    struct timespec t1, t2;
     bool Cflag = false, qflag = false, vflag = false;
     int c, cnt, ret;
     char *buf;
@@ -891,9 +892,9 @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
         return -EINVAL;
     }
 
-    gettimeofday(&t1, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t1);
     ret = do_aio_readv(blk, &qiov, offset, &total);
-    gettimeofday(&t2, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t2);
 
     if (ret < 0) {
         printf("readv failed: %s\n", strerror(-ret));
@@ -972,7 +973,7 @@ static const cmdinfo_t write_cmd = {
 
 static int write_f(BlockBackend *blk, int argc, char **argv)
 {
-    struct timeval t1, t2;
+    struct timespec t1, t2;
     bool Cflag = false, qflag = false, bflag = false;
     bool Pflag = false, zflag = false, cflag = false;
     int flags = 0;
@@ -1091,7 +1092,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
         buf = qemu_io_alloc(blk, count, pattern);
     }
 
-    gettimeofday(&t1, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t1);
     if (bflag) {
         ret = do_save_vmstate(blk, buf, offset, count, &total);
     } else if (zflag) {
@@ -1101,7 +1102,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
     } else {
         ret = do_pwrite(blk, buf, offset, count, flags, &total);
     }
-    gettimeofday(&t2, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t2);
 
     if (ret < 0) {
         printf("write failed: %s\n", strerror(-ret));
@@ -1160,7 +1161,7 @@ static const cmdinfo_t writev_cmd = {
 
 static int writev_f(BlockBackend *blk, int argc, char **argv)
 {
-    struct timeval t1, t2;
+    struct timespec t1, t2;
     bool Cflag = false, qflag = false;
     int flags = 0;
     int c, cnt, ret;
@@ -1213,9 +1214,9 @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
         return -EINVAL;
     }
 
-    gettimeofday(&t1, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t1);
     ret = do_aio_writev(blk, &qiov, offset, flags, &total);
-    gettimeofday(&t2, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t2);
 
     if (ret < 0) {
         printf("writev failed: %s\n", strerror(-ret));
@@ -1250,15 +1251,15 @@ struct aio_ctx {
     bool zflag;
     BlockAcctCookie acct;
     int pattern;
-    struct timeval t1;
+    struct timespec t1;
 };
 
 static void aio_write_done(void *opaque, int ret)
 {
     struct aio_ctx *ctx = opaque;
-    struct timeval t2;
+    struct timespec t2;
 
-    gettimeofday(&t2, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t2);
 
 
     if (ret < 0) {
@@ -1288,9 +1289,9 @@ out:
 static void aio_read_done(void *opaque, int ret)
 {
     struct aio_ctx *ctx = opaque;
-    struct timeval t2;
+    struct timespec t2;
 
-    gettimeofday(&t2, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t2);
 
     if (ret < 0) {
         printf("readv failed: %s\n", strerror(-ret));
@@ -1425,7 +1426,7 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
         return -EINVAL;
     }
 
-    gettimeofday(&ctx->t1, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &ctx->t1);
     block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
                      BLOCK_ACCT_READ);
     blk_aio_preadv(blk, ctx->offset, &ctx->qiov, 0, aio_read_done, ctx);
@@ -1570,7 +1571,7 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
             return -EINVAL;
         }
 
-        gettimeofday(&ctx->t1, NULL);
+        clock_gettime(CLOCK_MONOTONIC, &ctx->t1);
         block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
                          BLOCK_ACCT_WRITE);
 
@@ -1746,7 +1747,7 @@ static const cmdinfo_t discard_cmd = {
 
 static int discard_f(BlockBackend *blk, int argc, char **argv)
 {
-    struct timeval t1, t2;
+    struct timespec t1, t2;
     bool Cflag = false, qflag = false;
     int c, ret;
     int64_t offset, bytes;
@@ -1787,9 +1788,9 @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
         return -EINVAL;
     }
 
-    gettimeofday(&t1, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t1);
     ret = blk_pdiscard(blk, offset, bytes);
-    gettimeofday(&t2, NULL);
+    clock_gettime(CLOCK_MONOTONIC, &t2);
 
     if (ret < 0) {
         printf("discard failed: %s\n", strerror(-ret));
-- 
2.20.1



  parent reply	other threads:[~2019-05-30 10:18 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-30 10:15 [Qemu-devel] [PATCH v1 00/26] testing/next queue (iotests, docker, tests/vm) Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 01/26] editorconfig: add setting for shell scripts Alex Bennée
2019-05-30 18:15   ` Richard Henderson
2019-05-30 10:15 ` Alex Bennée [this message]
2019-05-30 18:41   ` [Qemu-devel] [PATCH v1 02/26] qemu-io-cmds: use clock_gettime for benchmarking Richard Henderson
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 03/26] tests: Run the iotests during "make check" again Alex Bennée
2019-06-07  9:33   ` Alex Bennée
2019-07-15 11:06     ` Thomas Huth
2019-07-15 11:58       ` Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 04/26] tests/docker: Update the Fedora image to Fedora 30 Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 05/26] tests/docker: Update the Fedora cross compile images to 30 Alex Bennée
2019-05-30 18:43   ` Richard Henderson
2019-05-31  6:54   ` Philippe Mathieu-Daudé
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 06/26] tests/docker: Update the Ubuntu image to 19.04 Alex Bennée
2019-05-30 18:44   ` Richard Henderson
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 07/26] .travis.yml: bump gcc sanitiser job to gcc-9 Alex Bennée
2019-05-31  7:56   ` Stefano Garzarella
2019-05-31  8:16     ` Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 08/26] .travis.yml: add clang ubsan job Alex Bennée
2019-05-31  6:21   ` Philippe Mathieu-Daudé
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 09/26] tests/vm: Use python configured on build Alex Bennée
2019-05-31  6:22   ` Philippe Mathieu-Daudé
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 10/26] tests/vm: Port basevm to Python 3 Alex Bennée
2019-05-31  6:22   ` Philippe Mathieu-Daudé
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 11/26] tests/vm: Fix build-centos docker-based tests run Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 12/26] tests/vm: Add missing variables on help Alex Bennée
2019-05-31  6:45   ` Philippe Mathieu-Daudé
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 13/26] scripts: use git archive in archive-source Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 14/26] tests/vm: python3 fixes Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 15/26] tests/vm: send proxy environment variables over ssh Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 16/26] tests/vm: use ssh with pty unconditionally Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 17/26] tests/vm: run test builds on snapshot Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 18/26] tests/vm: proper guest shutdown Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 19/26] tests/vm: add vm-boot-{ssh, serial}-<guest> targets Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 20/26] tests/vm: add DEBUG=1 to help text Alex Bennée
2019-05-31  6:49   ` Philippe Mathieu-Daudé
2019-05-31  8:15     ` Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 21/26] tests/vm: serial console support helpers Alex Bennée
2019-05-30 10:15 ` [Qemu-devel] [PATCH v1 22/26] tests/vm: openbsd autoinstall, using serial console Alex Bennée
2019-05-30 10:16 ` [Qemu-devel] [PATCH v1 23/26] tests/vm: freebsd " Alex Bennée
2019-05-30 10:16 ` [Qemu-devel] [PATCH v1 24/26] tests/vm: netbsd " Alex Bennée
2019-05-30 10:16 ` [Qemu-devel] [PATCH v1 25/26] tests/vm: fedora " Alex Bennée
2019-05-30 10:16 ` [Qemu-devel] [PATCH v1 26/26] tests/vm: ubuntu.i386: apt proxy setup Alex Bennée

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190530101603.22254-3-alex.bennee@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=kwolf@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).