[Libguestfs] [PATCH nbdkit 2/3] filters: stats: Measure time per operation

Nir Soffer nirsof at gmail.com
Sat Nov 30 00:17:06 UTC 2019


Previously we measured the total time and used it to calculate the rate
of different operations. This is incorrect and hides the real
throughput.  A more useful way is to measure the time we spent in each
operation.

Here is an example run with this change:

$ ./nbdkit --foreground \
    --unix /tmp/nbd.sock \
    --exportname '' \
    --filter stats \
    file file=/var/tmp/dst.img \
    statsfile=/dev/stderr \
    --run 'qemu-img convert -p -n -f raw -O raw -T none /var/tmp/fedora-30.img nbd:unix:/tmp/nbd.sock'
    (100.00/100%)
elapsed time: 2.150 s
write: 1271 ops, 1.14 GiB, 0.398 s, 2922.22 MiB/s
zero: 1027 ops, 4.86 GiB, 0.012 s, 414723.03 MiB/s
extents: 1 ops, 2.00 GiB, 0.000 s, 120470559.51 MiB/s

This show that the actual time waiting for storage was only 0.4 seconds,
but elapsed time was 2.1 seconds. I think the missing time is in flush()
which we do not measure yet.
---
 filters/stats/stats.c | 78 +++++++++++++++++++++++++++++++++----------
 1 file changed, 60 insertions(+), 18 deletions(-)

diff --git a/filters/stats/stats.c b/filters/stats/stats.c
index 45bedae..86439e7 100644
--- a/filters/stats/stats.c
+++ b/filters/stats/stats.c
@@ -60,12 +60,12 @@ static struct timeval start_t;
 
 /* This lock protects all the stats. */
 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-static uint64_t pread_ops, pread_bytes;
-static uint64_t pwrite_ops, pwrite_bytes;
-static uint64_t trim_ops, trim_bytes;
-static uint64_t zero_ops, zero_bytes;
-static uint64_t extents_ops, extents_bytes;
-static uint64_t cache_ops, cache_bytes;
+static uint64_t pread_ops, pread_bytes, pread_usecs;
+static uint64_t pwrite_ops, pwrite_bytes, pwrite_usecs;
+static uint64_t trim_ops, trim_bytes, trim_usecs;
+static uint64_t zero_ops, zero_bytes, zero_usecs;
+static uint64_t extents_ops, extents_bytes, extents_usecs;
+static uint64_t cache_ops, cache_bytes, cache_usecs;
 
 static inline double
 calc_mibps (uint64_t bytes, int64_t usecs)
@@ -79,23 +79,23 @@ print_stats (int64_t usecs)
   fprintf (fp, "elapsed time: %.3f s\n", usecs / USEC);
 
   if (pread_ops > 0)
-    fprintf (fp, "read: %" PRIu64 " ops, %.2f GiB, %.2f MiB/s\n",
-             pread_ops, pread_bytes / GiB, calc_mibps (pread_bytes, usecs));
+    fprintf (fp, "read: %" PRIu64 " ops, %.2f GiB, %.3f s, %.2f MiB/s\n",
+             pread_ops, pread_bytes / GiB, pread_usecs / USEC, calc_mibps (pread_bytes, pread_usecs));
   if (pwrite_ops > 0)
-    fprintf (fp, "write: %" PRIu64 " ops, %.2f GiB, %.2f MiB/s\n",
-             pwrite_ops, pwrite_bytes / GiB, calc_mibps (pwrite_bytes, usecs));
+    fprintf (fp, "write: %" PRIu64 " ops, %.2f GiB, %.3f s, %.2f MiB/s\n",
+             pwrite_ops, pwrite_bytes / GiB, pwrite_usecs / USEC, calc_mibps (pwrite_bytes, pwrite_usecs));
   if (trim_ops > 0)
-    fprintf (fp, "trim: %" PRIu64 " ops, %.2f GiB, %.2f MiB/s\n",
-             trim_ops, trim_bytes / GiB, calc_mibps (trim_bytes, usecs));
+    fprintf (fp, "trim: %" PRIu64 " ops, %.2f GiB, %.3f s, %.2f MiB/s\n",
+             trim_ops, trim_bytes / GiB, trim_usecs / USEC, calc_mibps (trim_bytes, trim_usecs));
   if (zero_ops > 0)
-    fprintf (fp, "zero: %" PRIu64 " ops, %.2f GiB, %.2f MiB/s\n",
-             zero_ops, zero_bytes / GiB, calc_mibps (zero_bytes, usecs));
+    fprintf (fp, "zero: %" PRIu64 " ops, %.2f GiB, %.3f s, %.2f MiB/s\n",
+             zero_ops, zero_bytes / GiB, zero_usecs / USEC, calc_mibps (zero_bytes, zero_usecs));
   if (extents_ops > 0)
-    fprintf (fp, "extents: %" PRIu64 " ops, %.2f GiB, %.2f MiB/s\n",
-             extents_ops, extents_bytes / GiB, calc_mibps (extents_bytes, usecs));
+    fprintf (fp, "extents: %" PRIu64 " ops, %.2f GiB, %.3f s, %.2f MiB/s\n",
+             extents_ops, extents_bytes / GiB, extents_usecs / USEC, calc_mibps (extents_bytes, extents_usecs));
   if (cache_ops > 0)
-    fprintf (fp, "cache: %" PRIu64 " ops, %.2f GiB, %.2f MiB/s\n",
-             cache_ops, cache_bytes / GiB, calc_mibps (cache_bytes, usecs));
+    fprintf (fp, "cache: %" PRIu64 " ops, %.2f GiB, %.3f s, %.2f MiB/s\n",
+             cache_ops, cache_bytes / GiB, cache_usecs / USEC, calc_mibps (cache_bytes, cache_usecs));
 
   fflush (fp);
 }
@@ -186,13 +186,20 @@ stats_pread (struct nbdkit_next_ops *next_ops, void *nxdata,
              void *handle, void *buf, uint32_t count, uint64_t offset,
              uint32_t flags, int *err)
 {
+  struct timeval start, end;
+  int64_t usecs;
   int r;
 
+  gettimeofday (&start, NULL);
   r = next_ops->pread (nxdata, buf, count, offset, flags, err);
   if (r == 0) {
+    gettimeofday (&end, NULL);
+    usecs = tvdiff_usec(&start, &end);
+
     ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
     pread_ops++;
     pread_bytes += count;
+    pread_usecs += usecs;
   }
   return r;
 }
@@ -204,13 +211,20 @@ stats_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata,
               const void *buf, uint32_t count, uint64_t offset,
               uint32_t flags, int *err)
 {
+  struct timeval start, end;
+  int64_t usecs;
   int r;
 
+  gettimeofday (&start, NULL);
   r = next_ops->pwrite (nxdata, buf, count, offset, flags, err);
   if (r == 0) {
+    gettimeofday (&end, NULL);
+    usecs = tvdiff_usec(&start, &end);
+
     ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
     pwrite_ops++;
     pwrite_bytes += count;
+    pwrite_usecs += usecs;
   }
   return r;
 }
@@ -222,13 +236,20 @@ stats_trim (struct nbdkit_next_ops *next_ops, void *nxdata,
             uint32_t count, uint64_t offset, uint32_t flags,
             int *err)
 {
+  struct timeval start, end;
+  int64_t usecs;
   int r;
 
+  gettimeofday (&start, NULL);
   r = next_ops->trim (nxdata, count, offset, flags, err);
   if (r == 0) {
+    gettimeofday (&end, NULL);
+    usecs = tvdiff_usec(&start, &end);
+
     ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
     trim_ops++;
     trim_bytes += count;
+    trim_usecs += usecs;
   }
   return r;
 }
@@ -240,13 +261,20 @@ stats_zero (struct nbdkit_next_ops *next_ops, void *nxdata,
             uint32_t count, uint64_t offset, uint32_t flags,
             int *err)
 {
+  struct timeval start, end;
+  int64_t usecs;
   int r;
 
+  gettimeofday (&start, NULL);
   r = next_ops->zero (nxdata, count, offset, flags, err);
   if (r == 0) {
+    gettimeofday (&end, NULL);
+    usecs = tvdiff_usec(&start, &end);
+
     ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
     zero_ops++;
     zero_bytes += count;
+    zero_usecs += usecs;
   }
   return r;
 }
@@ -258,10 +286,16 @@ stats_extents (struct nbdkit_next_ops *next_ops, void *nxdata,
                uint32_t count, uint64_t offset, uint32_t flags,
                struct nbdkit_extents *extents, int *err)
 {
+  struct timeval start, end;
+  int64_t usecs;
   int r;
 
+  gettimeofday (&start, NULL);
   r = next_ops->extents (nxdata, count, offset, flags, extents, err);
   if (r == 0) {
+    gettimeofday (&end, NULL);
+    usecs = tvdiff_usec(&start, &end);
+
     ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
     extents_ops++;
     /* XXX There's a case for trying to determine how long the extents
@@ -269,6 +303,7 @@ stats_extents (struct nbdkit_next_ops *next_ops, void *nxdata,
      * the complex rules in the protocol.
      */
     extents_bytes += count;
+    extents_usecs += usecs;
   }
   return r;
 }
@@ -280,13 +315,20 @@ stats_cache (struct nbdkit_next_ops *next_ops, void *nxdata,
              uint32_t count, uint64_t offset, uint32_t flags,
              int *err)
 {
+  struct timeval start, end;
+  int64_t usecs;
   int r;
 
+  gettimeofday (&start, NULL);
   r = next_ops->cache (nxdata, count, offset, flags, err);
   if (r == 0) {
+    gettimeofday (&end, NULL);
+    usecs = tvdiff_usec(&start, &end);
+
     ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
     cache_ops++;
     cache_bytes += count;
+    cache_usecs += usecs;
   }
   return r;
 }
-- 
2.21.0





More information about the Libguestfs mailing list