X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=gettime.c;h=89a3a016e4c871a767365f96318392a65ec30ba6;hb=fa80feae51331fb170e784459fa1359d7ec3a963;hp=2037354d0116a122ffb9b698c55b7b9aacbce86b;hpb=783a3eb15f143d26eed5fd1c943f238057f3ee52;p=fio.git diff --git a/gettime.c b/gettime.c index 2037354d..89a3a016 100644 --- a/gettime.c +++ b/gettime.c @@ -15,16 +15,13 @@ #ifdef ARCH_HAVE_CPU_CLOCK static unsigned long cycles_per_usec; static unsigned long last_cycles; +int tsc_reliable = 0; #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; +int fio_clock_source_set = 0; #ifdef FIO_DEBUG_TIME @@ -213,15 +210,17 @@ static unsigned long get_cycles_per_usec(void) return c_e - c_s; } +#define NR_TIME_ITERS 50 + static void calibrate_cpu_clock(void) { double delta, mean, S; - unsigned long avg, cycles[10]; + unsigned long avg, cycles[NR_TIME_ITERS]; int i, samples; cycles[0] = get_cycles_per_usec(); S = delta = mean = 0.0; - for (i = 0; i < 10; i++) { + for (i = 0; i < NR_TIME_ITERS; i++) { cycles[i] = get_cycles_per_usec(); delta = cycles[i] - mean; if (delta) { @@ -230,10 +229,10 @@ static void calibrate_cpu_clock(void) } } - S = sqrt(S / (10 - 1.0)); + S = sqrt(S / (NR_TIME_ITERS - 1.0)); samples = avg = 0; - for (i = 0; i < 10; i++) { + for (i = 0; i < NR_TIME_ITERS; i++) { double this = cycles[i]; if ((fmax(this, mean) - fmin(this, mean)) > S) @@ -242,10 +241,10 @@ static void calibrate_cpu_clock(void) avg += this; } - S /= 10.0; - mean /= 10.0; + S /= (double) NR_TIME_ITERS; + mean /= (double) NR_TIME_ITERS; - for (i = 0; i < 10; i++) + for (i = 0; i < NR_TIME_ITERS; i++) dprint(FD_TIME, "cycles[%d]=%lu\n", i, cycles[i] / 10); avg /= (samples * 10); @@ -253,7 +252,6 @@ static void calibrate_cpu_clock(void) dprint(FD_TIME, "mean=%f, S=%f\n", mean, S); cycles_per_usec = avg; - } #else static void calibrate_cpu_clock(void) @@ -265,68 +263,81 @@ void fio_clock_init(void) { last_tv_valid = 0; calibrate_cpu_clock(); + + /* + * If the arch sets tsc_reliable != 0, then it must be good enough + * to use as THE clock source. For x86 CPUs, this means the TSC + * runs at a constant rate and is synced across CPU cores. + */ + if (tsc_reliable) { + if (!fio_clock_source_set) + fio_clock_source = CS_CPUCLOCK; + } else if (fio_clock_source == CS_CPUCLOCK) + log_info("fio: clocksource=cpu may not be reliable\n"); } -void fio_gtod_init(void) +unsigned long long utime_since(struct timeval *s, struct timeval *e) { - fio_tv = smalloc(sizeof(struct timeval)); - assert(fio_tv); + long sec, usec; + unsigned long long ret; + + sec = e->tv_sec - s->tv_sec; + usec = e->tv_usec - s->tv_usec; + if (sec > 0 && usec < 0) { + sec--; + usec += 1000000; + } + + /* + * time warp bug on some kernels? + */ + if (sec < 0 || (sec == 0 && usec < 0)) + return 0; + + ret = sec * 1000000ULL + usec; + + return ret; } -void fio_gtod_update(void) +unsigned long long utime_since_now(struct timeval *s) { - gettimeofday(fio_tv, NULL); + struct timeval t; + + fio_gettime(&t, NULL); + return utime_since(s, &t); } -static void *gtod_thread_main(void *data) +unsigned long mtime_since(struct timeval *s, struct timeval *e) { - struct fio_mutex *mutex = data; - - fio_mutex_up(mutex); + long sec, usec, ret; - /* - * 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; + sec = e->tv_sec - s->tv_sec; + usec = e->tv_usec - s->tv_usec; + if (sec > 0 && usec < 0) { + sec--; + usec += 1000000; } - return NULL; + if (sec < 0 || (sec == 0 && usec < 0)) + return 0; + + sec *= 1000UL; + usec /= 1000UL; + ret = sec + usec; + + return ret; } -int fio_start_gtod_thread(void) +unsigned long mtime_since_now(struct timeval *s) { - struct fio_mutex *mutex; - pthread_attr_t attr; - int ret; - - mutex = fio_mutex_init(0); - 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; - } + struct timeval t; + void *p = __builtin_return_address(0); - ret = pthread_detach(gtod_thread); - if (ret) { - log_err("Can't detatch gtod thread: %s\n", strerror(ret)); - goto err; - } + fio_gettime(&t, p); + return mtime_since(s, &t); +} - 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; +unsigned long time_since_now(struct timeval *s) +{ + return mtime_since_now(s) / 1000; }