summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@fb.com>2014-12-16 22:40:37 -0700
committerJens Axboe <axboe@fb.com>2014-12-16 22:40:37 -0700
commitb3fa625b38a638cd1783e9fdcac1b958e37e48fa (patch)
tree5f4509ceae403f0c6e300b7c4bf5e18b0a8412a3
parent79c896a122a7a39b840257215e622bdeff8272f1 (diff)
downloadfio-b3fa625b38a638cd1783e9fdcac1b958e37e48fa.tar.gz
fio-b3fa625b38a638cd1783e9fdcac1b958e37e48fa.tar.bz2
gettime: fix overflow in cycle to usec conversion
If this multiplication overflows: usecs = (t * inv_cycles_per_usec) / 16777216UL; then usecs is 2^64/2^24, which is 1099511627776. Divide that by 10^6 to get seconds, and that is 1099511. Since we cached the old value previously, we'd get stuck with this amount of seconds. To avoid turning this into an expensive division, have a check and only divide if we have to. This avoids the overflow. Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--gettime.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/gettime.c b/gettime.c
index e2746711..30513e03 100644
--- a/gettime.c
+++ b/gettime.c
@@ -16,6 +16,7 @@
#if defined(ARCH_HAVE_CPU_CLOCK) && !defined(ARCH_CPU_CLOCK_CYCLES_PER_USEC)
static unsigned long cycles_per_usec;
static unsigned long inv_cycles_per_usec;
+static uint64_t max_cycles_for_mult;
#endif
int tsc_reliable = 0;
@@ -182,7 +183,10 @@ static void __fio_gettime(struct timeval *tp)
#ifdef ARCH_CPU_CLOCK_CYCLES_PER_USEC
usecs = t / ARCH_CPU_CLOCK_CYCLES_PER_USEC;
#else
- usecs = (t * inv_cycles_per_usec) / 16777216UL;
+ if (t < max_cycles_for_mult)
+ usecs = (t * inv_cycles_per_usec) / 16777216UL;
+ else
+ usecs = t / cycles_per_usec;
#endif
tp->tv_sec = usecs / 1000000;
tp->tv_usec = usecs % 1000000;
@@ -296,6 +300,7 @@ static int calibrate_cpu_clock(void)
cycles_per_usec = avg;
inv_cycles_per_usec = 16777216UL / cycles_per_usec;
+ max_cycles_for_mult = ~0ULL / inv_cycles_per_usec;
dprint(FD_TIME, "inv_cycles_per_usec=%lu\n", inv_cycles_per_usec);
return 0;
}