Optimize fio_gettime_offload()
authorBart Van Assche <bvanassche@acm.org>
Sun, 21 Jun 2020 21:31:08 +0000 (14:31 -0700)
committerBart Van Assche <bvanassche@acm.org>
Mon, 22 Jun 2020 02:47:25 +0000 (19:47 -0700)
This patch not only an optimization but also a bug fix because it guarantees
that fio_gettime_offload() never returns an inconsistent timestamp, something
that could happen before. In this context inconsistent means returning the
.tv_sec value from one gettimeofday() call and the .tv_usec value from another
gettimeofday() call.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
gettime-thread.c
gettime.h
t/debug.c

index 0a2cc6c..953e4e6 100644 (file)
@@ -2,9 +2,10 @@
 #include <time.h>
 
 #include "fio.h"
+#include "lib/seqlock.h"
 #include "smalloc.h"
 
-struct timespec *fio_ts = NULL;
+struct fio_ts *fio_ts;
 int fio_gtod_offload = 0;
 static pthread_t gtod_thread;
 static os_cpu_mask_t fio_gtod_cpumask;
@@ -19,15 +20,17 @@ void fio_gtod_init(void)
 
 static void fio_gtod_update(void)
 {
-       if (fio_ts) {
-               struct timeval __tv;
-
-               gettimeofday(&__tv, NULL);
-               fio_ts->tv_sec = __tv.tv_sec;
-               write_barrier();
-               fio_ts->tv_nsec = __tv.tv_usec * 1000;
-               write_barrier();
-       }
+       struct timeval __tv;
+
+       if (!fio_ts)
+               return;
+
+       gettimeofday(&__tv, NULL);
+
+       write_seqlock_begin(&fio_ts->seqlock);
+       fio_ts->ts.tv_sec = __tv.tv_sec;
+       fio_ts->ts.tv_nsec = __tv.tv_usec * 1000;
+       write_seqlock_end(&fio_ts->seqlock);
 }
 
 struct gtod_cpu_data {
index f92ee8c..c55f5cb 100644 (file)
--- a/gettime.h
+++ b/gettime.h
@@ -4,6 +4,7 @@
 #include <sys/time.h>
 
 #include "arch/arch.h"
+#include "lib/seqlock.h"
 
 /*
  * Clock sources
@@ -22,20 +23,22 @@ extern int fio_start_gtod_thread(void);
 extern int fio_monotonic_clocktest(int debug);
 extern void fio_local_clock_init(void);
 
-extern struct timespec *fio_ts;
+extern struct fio_ts {
+       struct seqlock seqlock;
+       struct timespec ts;
+} *fio_ts;
 
 static inline int fio_gettime_offload(struct timespec *ts)
 {
-       time_t last_sec;
+       unsigned int seq;
 
        if (!fio_ts)
                return 0;
 
        do {
-               read_barrier();
-               last_sec = ts->tv_sec = fio_ts->tv_sec;
-               ts->tv_nsec = fio_ts->tv_nsec;
-       } while (fio_ts->tv_sec != last_sec);
+               seq = read_seqlock_begin(&fio_ts->seqlock);
+               *ts = fio_ts->ts;
+       } while (read_seqlock_retry(&fio_ts->seqlock, seq));
 
        return 1;
 }
index 8965cfb..0c91336 100644 (file)
--- a/t/debug.c
+++ b/t/debug.c
@@ -1,7 +1,7 @@
 #include <stdio.h>
 
 FILE *f_err;
-struct timespec *fio_ts = NULL;
+void *fio_ts;
 unsigned long fio_debug = 0;
 
 void __dprint(int type, const char *str, ...)