Merge branch 'master' of https://github.com/celestinechen/fio
[fio.git] / gettime.c
index 272a3e6244527c27d59a06ff99fb4871424a063b..5ca3120633dd409c669da255dd7e422258b3021d 100644 (file)
--- a/gettime.c
+++ b/gettime.c
@@ -127,18 +127,33 @@ static void fio_init gtod_init(void)
 
 #endif /* FIO_DEBUG_TIME */
 
-#ifdef CONFIG_CLOCK_GETTIME
-static int fill_clock_gettime(struct timespec *ts)
+/*
+ * Queries the value of the monotonic clock if a monotonic clock is available
+ * or the wall clock time if no monotonic clock is available. Returns 0 if
+ * querying the clock succeeded or -1 if querying the clock failed.
+ */
+int fio_get_mono_time(struct timespec *ts)
 {
-#if defined(CONFIG_CLOCK_MONOTONIC_RAW)
-       return clock_gettime(CLOCK_MONOTONIC_RAW, ts);
-#elif defined(CONFIG_CLOCK_MONOTONIC)
-       return clock_gettime(CLOCK_MONOTONIC, ts);
+       int ret;
+
+#ifdef CONFIG_CLOCK_GETTIME
+#if defined(CONFIG_CLOCK_MONOTONIC)
+       ret = clock_gettime(CLOCK_MONOTONIC, ts);
 #else
-       return clock_gettime(CLOCK_REALTIME, ts);
+       ret = clock_gettime(CLOCK_REALTIME, ts);
 #endif
-}
+#else
+       struct timeval tv;
+
+       ret = gettimeofday(&tv, NULL);
+       if (ret == 0) {
+               ts->tv_sec = tv.tv_sec;
+               ts->tv_nsec = tv.tv_usec * 1000;
+       }
 #endif
+       assert(ret <= 0);
+       return ret;
+}
 
 static void __fio_gettime(struct timespec *tp)
 {
@@ -155,8 +170,8 @@ static void __fio_gettime(struct timespec *tp)
 #endif
 #ifdef CONFIG_CLOCK_GETTIME
        case CS_CGETTIME: {
-               if (fill_clock_gettime(tp) < 0) {
-                       log_err("fio: clock_gettime fails\n");
+               if (fio_get_mono_time(tp) < 0) {
+                       log_err("fio: fio_get_mono_time() fails\n");
                        assert(0);
                }
                break;
@@ -224,19 +239,13 @@ static unsigned long get_cycles_per_msec(void)
 {
        struct timespec s, e;
        uint64_t c_s, c_e;
-       enum fio_cs old_cs = fio_clock_source;
        uint64_t elapsed;
 
-#ifdef CONFIG_CLOCK_GETTIME
-       fio_clock_source = CS_CGETTIME;
-#else
-       fio_clock_source = CS_GTOD;
-#endif
-       __fio_gettime(&s);
+       fio_get_mono_time(&s);
 
        c_s = get_cpu_clock();
        do {
-               __fio_gettime(&e);
+               fio_get_mono_time(&e);
                c_e = get_cpu_clock();
 
                elapsed = ntime_since(&s, &e);
@@ -244,7 +253,6 @@ static unsigned long get_cycles_per_msec(void)
                        break;
        } while (1);
 
-       fio_clock_source = old_cs;
        return (c_e - c_s) * 1000000 / elapsed;
 }
 
@@ -305,7 +313,7 @@ static int calibrate_cpu_clock(void)
 
        max_ticks = MAX_CLOCK_SEC * cycles_per_msec * 1000ULL;
        max_mult = ULLONG_MAX / max_ticks;
-       dprint(FD_TIME, "\n\nmax_ticks=%llu, __builtin_clzll=%d, "
+       dprint(FD_TIME, "max_ticks=%llu, __builtin_clzll=%d, "
                        "max_mult=%llu\n", max_ticks,
                        __builtin_clzll(max_ticks), max_mult);
 
@@ -327,7 +335,7 @@ static int calibrate_cpu_clock(void)
 
        /*
         * Find the greatest power of 2 clock ticks that is less than the
-        * ticks in MAX_CLOCK_SEC_2STAGE
+        * ticks in MAX_CLOCK_SEC
         */
        max_cycles_shift = max_cycles_mask = 0;
        tmp = MAX_CLOCK_SEC * 1000ULL * cycles_per_msec;
@@ -371,7 +379,7 @@ static int calibrate_cpu_clock(void)
 }
 #endif // ARCH_HAVE_CPU_CLOCK
 
-#ifndef CONFIG_TLS_THREAD
+#if defined(ARCH_HAVE_CPU_CLOCK) && !defined(CONFIG_TLS_THREAD)
 void fio_local_clock_init(void)
 {
        struct tv_valid *t;
@@ -398,7 +406,7 @@ void fio_clock_init(void)
        if (fio_clock_source == fio_clock_source_inited)
                return;
 
-#ifndef CONFIG_TLS_THREAD
+#if defined(ARCH_HAVE_CPU_CLOCK) && !defined(CONFIG_TLS_THREAD)
        if (pthread_key_create(&tv_tls_key, kill_tv_tls_key))
                log_err("fio: can't create TLS key\n");
 #endif
@@ -423,22 +431,22 @@ void fio_clock_init(void)
 
 uint64_t ntime_since(const struct timespec *s, const struct timespec *e)
 {
-       int64_t sec, nsec;
+       int64_t sec, nsec;
 
-       sec = e->tv_sec - s->tv_sec;
-       nsec = e->tv_nsec - s->tv_nsec;
-       if (sec > 0 && nsec < 0) {
-              sec--;
-              nsec += 1000000000LL;
-       }
+       sec = e->tv_sec - s->tv_sec;
+       nsec = e->tv_nsec - s->tv_nsec;
+       if (sec > 0 && nsec < 0) {
+               sec--;
+               nsec += 1000000000LL;
+       }
 
        /*
        * time warp bug on some kernels?
        */
-       if (sec < 0 || (sec == 0 && nsec < 0))
-              return 0;
+       if (sec < 0 || (sec == 0 && nsec < 0))
+               return 0;
 
-       return nsec + (sec * 1000000000LL);
+       return nsec + (sec * 1000000000LL);
 }
 
 uint64_t ntime_since_now(const struct timespec *s)
@@ -516,23 +524,33 @@ uint64_t mtime_since_now(const struct timespec *s)
        return mtime_since(s, &t);
 }
 
-uint64_t mtime_since(const struct timespec *s, const struct timespec *e)
+/*
+ * Returns *e - *s in milliseconds as a signed integer. Note: rounding is
+ * asymmetric. If the difference yields +1 ns then 0 is returned. If the
+ * difference yields -1 ns then -1 is returned.
+ */
+int64_t rel_time_since(const struct timespec *s, const struct timespec *e)
 {
-       int64_t sec, usec;
+       int64_t sec, nsec;
 
        sec = e->tv_sec - s->tv_sec;
-       usec = (e->tv_nsec - s->tv_nsec) / 1000;
-       if (sec > 0 && usec < 0) {
+       nsec = e->tv_nsec - s->tv_nsec;
+       if (nsec < 0) {
                sec--;
-               usec += 1000000;
+               nsec += 1000ULL * 1000 * 1000;
        }
+       assert(0 <= nsec && nsec < 1000ULL * 1000 * 1000);
 
-       if (sec < 0 || (sec == 0 && usec < 0))
-               return 0;
+       return sec * 1000 + nsec / (1000 * 1000);
+}
 
-       sec *= 1000;
-       usec /= 1000;
-       return sec + usec;
+/*
+ * Returns *e - *s in milliseconds as an unsigned integer. Returns 0 if
+ * *e < *s.
+ */
+uint64_t mtime_since(const struct timespec *s, const struct timespec *e)
+{
+       return max(rel_time_since(s, e), (int64_t)0);
 }
 
 uint64_t time_since_now(const struct timespec *s)
@@ -605,7 +623,7 @@ static void *clock_thread_fn(void *data)
                        seq = *t->seq;
                        if (seq == UINT_MAX)
                                break;
-                       __sync_synchronize();
+                       tsc_barrier();
                        tsc = get_cpu_clock();
                } while (seq != atomic32_compare_and_swap(t->seq, seq, seq + 1));
 
@@ -653,12 +671,21 @@ static int clock_cmp(const void *p1, const void *p2)
 int fio_monotonic_clocktest(int debug)
 {
        struct clock_thread *cthreads;
-       unsigned int nr_cpus = cpus_online();
+       unsigned int seen_cpus, nr_cpus = cpus_configured();
        struct clock_entry *entries;
        unsigned long nr_entries, tentries, failed = 0;
        struct clock_entry *prev, *this;
        uint32_t seq = 0;
        unsigned int i;
+       os_cpu_mask_t mask;
+
+#ifdef FIO_HAVE_GET_THREAD_AFFINITY
+       fio_get_thread_affinity(mask);
+#else
+       memset(&mask, 0, sizeof(mask));
+       for (i = 0; i < nr_cpus; i++)
+               fio_cpu_set(&mask, i);
+#endif
 
        if (debug) {
                log_info("cs: reliable_tsc: %s\n", tsc_reliable ? "yes" : "no");
@@ -685,25 +712,31 @@ int fio_monotonic_clocktest(int debug)
        if (debug)
                log_info("cs: Testing %u CPUs\n", nr_cpus);
 
+       seen_cpus = 0;
        for (i = 0; i < nr_cpus; i++) {
                struct clock_thread *t = &cthreads[i];
 
+               if (!fio_cpu_isset(&mask, i))
+                       continue;
                t->cpu = i;
                t->debug = debug;
                t->seq = &seq;
                t->nr_entries = nr_entries;
-               t->entries = &entries[i * nr_entries];
+               t->entries = &entries[seen_cpus * nr_entries];
                __fio_sem_init(&t->lock, FIO_SEM_LOCKED);
                if (pthread_create(&t->thread, NULL, clock_thread_fn, t)) {
                        failed++;
                        nr_cpus = i;
                        break;
                }
+               seen_cpus++;
        }
 
        for (i = 0; i < nr_cpus; i++) {
                struct clock_thread *t = &cthreads[i];
 
+               if (!fio_cpu_isset(&mask, i))
+                       continue;
                fio_sem_up(&t->lock);
        }
 
@@ -711,6 +744,8 @@ int fio_monotonic_clocktest(int debug)
                struct clock_thread *t = &cthreads[i];
                void *ret;
 
+               if (!fio_cpu_isset(&mask, i))
+                       continue;
                pthread_join(t->thread, &ret);
                if (ret)
                        failed++;
@@ -724,6 +759,7 @@ int fio_monotonic_clocktest(int debug)
                goto err;
        }
 
+       tentries = nr_entries * seen_cpus;
        qsort(entries, tentries, sizeof(struct clock_entry), clock_cmp);
 
        /* silence silly gcc */