X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=gettime.c;h=5b4928758b47f83c729082e399820ae2edc09a26;hp=08d2d2b3b1205a56543ec6aef00e52b37711d622;hb=1e48a4eabd8835ba8a3c98f52bf2738db2751787;hpb=c223da83e253b0057bb029bf4fbb55a05844215c diff --git a/gettime.c b/gettime.c index 08d2d2b3..5b492875 100644 --- a/gettime.c +++ b/gettime.c @@ -5,22 +5,26 @@ #include #include #include +#include #include "fio.h" #include "smalloc.h" #include "hash.h" +#ifdef ARCH_HAVE_CPU_CLOCK static unsigned long cycles_per_usec; -static struct timeval last_tv; static unsigned long last_cycles; +#endif +static struct timeval last_tv; static int last_tv_valid; static struct timeval *fio_tv; int fio_gtod_offload = 0; int fio_gtod_cpu = -1; +static pthread_t gtod_thread; -enum fio_cs fio_clock_source = CS_GTOD; +enum fio_cs fio_clock_source = FIO_PREFERRED_CLOCK_SOURCE; #ifdef FIO_DEBUG_TIME @@ -137,7 +141,11 @@ void fio_gettime(struct timeval *tp, void fio_unused *caller) case CS_CGETTIME: { struct timespec ts; +#ifdef FIO_HAVE_CLOCK_MONOTONIC + if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { +#else if (clock_gettime(CLOCK_REALTIME, &ts) < 0) { +#endif log_err("fio: clock_gettime fails\n"); assert(0); } @@ -183,6 +191,7 @@ void fio_gettime(struct timeval *tp, void fio_unused *caller) memcpy(&last_tv, tp, sizeof(*tp)); } +#ifdef ARCH_HAVE_CPU_CLOCK static unsigned long get_cycles_per_usec(void) { struct timeval s, e; @@ -204,14 +213,12 @@ static unsigned long get_cycles_per_usec(void) return c_e - c_s; } -void fio_clock_init(void) +static void calibrate_cpu_clock(void) { double delta, mean, S; unsigned long avg, cycles[10]; int i, samples; - last_tv_valid = 0; - cycles[0] = get_cycles_per_usec(); S = delta = mean = 0.0; for (i = 0; i < 10; i++) { @@ -229,7 +236,7 @@ void fio_clock_init(void) for (i = 0; i < 10; i++) { double this = cycles[i]; - if ((max(this, mean) - min(this, mean)) > S) + if ((fmax(this, mean) - fmin(this, mean)) > S) continue; samples++; avg += this; @@ -246,6 +253,18 @@ void fio_clock_init(void) dprint(FD_TIME, "mean=%f, S=%f\n", mean, S); cycles_per_usec = avg; + +} +#else +static void calibrate_cpu_clock(void) +{ +} +#endif + +void fio_clock_init(void) +{ + last_tv_valid = 0; + calibrate_cpu_clock(); } void fio_gtod_init(void) @@ -254,7 +273,60 @@ void fio_gtod_init(void) assert(fio_tv); } -void fio_gtod_update(void) +static void fio_gtod_update(void) { gettimeofday(fio_tv, NULL); } + +static void *gtod_thread_main(void *data) +{ + struct fio_mutex *mutex = data; + + fio_mutex_up(mutex); + + /* + * As long as we have jobs around, update the clock. It would be nice + * to have some way of NOT hammering that CPU with gettimeofday(), + * but I'm not sure what to use outside of a simple CPU nop to relax + * it - we don't want to lose precision. + */ + while (threads) { + fio_gtod_update(); + nop; + } + + return NULL; +} + +int fio_start_gtod_thread(void) +{ + struct fio_mutex *mutex; + pthread_attr_t attr; + int ret; + + mutex = fio_mutex_init(FIO_MUTEX_LOCKED); + if (!mutex) + return 1; + + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); + ret = pthread_create(>od_thread, &attr, gtod_thread_main, NULL); + pthread_attr_destroy(&attr); + if (ret) { + log_err("Can't create gtod thread: %s\n", strerror(ret)); + goto err; + } + + ret = pthread_detach(gtod_thread); + if (ret) { + log_err("Can't detatch gtod thread: %s\n", strerror(ret)); + goto err; + } + + dprint(FD_MUTEX, "wait on startup_mutex\n"); + fio_mutex_down(mutex); + dprint(FD_MUTEX, "done waiting on startup_mutex\n"); +err: + fio_mutex_remove(mutex); + return ret; +}