Flesh out time_*() API.
diff --git a/Makefile.in b/Makefile.in
index c4f8cf9..e314a6f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -116,7 +116,7 @@
$(srcroot)test/src/mtx.c $(srcroot)test/src/mq.c \
$(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \
$(srcroot)test/src/thd.c $(srcroot)test/src/timer.c
-C_UTIL_INTEGRATION_SRCS := $(srcroot)src/util.c
+C_UTIL_INTEGRATION_SRCS := $(srcroot)src/time.c $(srcroot)src/util.c
TESTS_UNIT := $(srcroot)test/unit/atomic.c \
$(srcroot)test/unit/bitmap.c \
$(srcroot)test/unit/ckh.c \
diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt
index 8b1fd45..4c40af6 100644
--- a/include/jemalloc/internal/private_symbols.txt
+++ b/include/jemalloc/internal/private_symbols.txt
@@ -460,6 +460,18 @@
tcache_stats_merge
thread_allocated_cleanup
thread_deallocated_cleanup
+ticker_init
+ticker_tick
+time_add
+time_compare
+time_copy
+time_divide
+time_idivide
+time_imultiply
+time_init
+time_nsec
+time_sec
+time_subtract
time_update
tsd_arena_get
tsd_arena_set
diff --git a/include/jemalloc/internal/time.h b/include/jemalloc/internal/time.h
index e3e6c5f..a290f38 100644
--- a/include/jemalloc/internal/time.h
+++ b/include/jemalloc/internal/time.h
@@ -1,8 +1,11 @@
+/******************************************************************************/
+#ifdef JEMALLOC_H_TYPES
+
#define JEMALLOC_CLOCK_GETTIME defined(_POSIX_MONOTONIC_CLOCK) \
&& _POSIX_MONOTONIC_CLOCK >= 0
-/******************************************************************************/
-#ifdef JEMALLOC_H_TYPES
+/* Maximum supported number of seconds (~584 years). */
+#define TIME_SEC_MAX 18446744072
#endif /* JEMALLOC_H_TYPES */
/******************************************************************************/
@@ -12,6 +15,17 @@
/******************************************************************************/
#ifdef JEMALLOC_H_EXTERNS
+void time_init(struct timespec *time, time_t sec, long nsec);
+time_t time_sec(const struct timespec *time);
+long time_nsec(const struct timespec *time);
+void time_copy(struct timespec *time, const struct timespec *source);
+int time_compare(const struct timespec *a, const struct timespec *b);
+void time_add(struct timespec *time, const struct timespec *addend);
+void time_subtract(struct timespec *time, const struct timespec *subtrahend);
+void time_imultiply(struct timespec *time, uint64_t multiplier);
+void time_idivide(struct timespec *time, uint64_t divisor);
+uint64_t time_divide(const struct timespec *time,
+ const struct timespec *divisor);
bool time_update(struct timespec *time);
#endif /* JEMALLOC_H_EXTERNS */
diff --git a/src/time.c b/src/time.c
index 2147c52..3f93038 100644
--- a/src/time.c
+++ b/src/time.c
@@ -1,11 +1,160 @@
#include "jemalloc/internal/jemalloc_internal.h"
+#define BILLION 1000000000
+
+UNUSED static bool
+time_valid(const struct timespec *time)
+{
+
+ if (time->tv_sec > TIME_SEC_MAX)
+ return (false);
+ if (time->tv_nsec >= BILLION)
+ return (false);
+
+ return (true);
+}
+
+void
+time_init(struct timespec *time, time_t sec, long nsec)
+{
+
+ time->tv_sec = sec;
+ time->tv_nsec = nsec;
+
+ assert(time_valid(time));
+}
+
+time_t
+time_sec(const struct timespec *time)
+{
+
+ assert(time_valid(time));
+
+ return (time->tv_sec);
+}
+
+long
+time_nsec(const struct timespec *time)
+{
+
+ assert(time_valid(time));
+
+ return (time->tv_nsec);
+}
+
+void
+time_copy(struct timespec *time, const struct timespec *source)
+{
+
+ assert(time_valid(source));
+
+ *time = *source;
+}
+
+int
+time_compare(const struct timespec *a, const struct timespec *b)
+{
+ int ret;
+
+ assert(time_valid(a));
+ assert(time_valid(b));
+
+ ret = (a->tv_sec > b->tv_sec) - (a->tv_sec < b->tv_sec);
+ if (ret == 0)
+ ret = (a->tv_nsec > b->tv_nsec) - (a->tv_nsec < b->tv_nsec);
+
+ return (ret);
+}
+
+void
+time_add(struct timespec *time, const struct timespec *addend)
+{
+
+ assert(time_valid(time));
+ assert(time_valid(addend));
+
+ time->tv_sec += addend->tv_sec;
+ time->tv_nsec += addend->tv_nsec;
+ if (time->tv_nsec >= BILLION) {
+ time->tv_sec++;
+ time->tv_nsec -= BILLION;
+ }
+
+ assert(time_valid(time));
+}
+
+void
+time_subtract(struct timespec *time, const struct timespec *subtrahend)
+{
+
+ assert(time_valid(time));
+ assert(time_valid(subtrahend));
+ assert(time_compare(time, subtrahend) >= 0);
+
+ time->tv_sec -= subtrahend->tv_sec;
+ if (time->tv_nsec < subtrahend->tv_nsec) {
+ time->tv_sec--;
+ time->tv_nsec += BILLION;
+ }
+ time->tv_nsec -= subtrahend->tv_nsec;
+}
+
+void
+time_imultiply(struct timespec *time, uint64_t multiplier)
+{
+ time_t sec;
+ uint64_t nsec;
+
+ assert(time_valid(time));
+
+ sec = time->tv_sec * multiplier;
+ nsec = time->tv_nsec * multiplier;
+ sec += nsec / BILLION;
+ nsec %= BILLION;
+ time_init(time, sec, (long)nsec);
+
+ assert(time_valid(time));
+}
+
+void
+time_idivide(struct timespec *time, uint64_t divisor)
+{
+ time_t sec;
+ uint64_t nsec;
+
+ assert(time_valid(time));
+
+ sec = time->tv_sec / divisor;
+ nsec = ((time->tv_sec % divisor) * BILLION + time->tv_nsec) / divisor;
+ sec += nsec / BILLION;
+ nsec %= BILLION;
+ time_init(time, sec, (long)nsec);
+
+ assert(time_valid(time));
+}
+
+uint64_t
+time_divide(const struct timespec *time, const struct timespec *divisor)
+{
+ uint64_t t, d;
+
+ assert(time_valid(time));
+ assert(time_valid(divisor));
+
+ t = time_sec(time) * BILLION + time_nsec(time);
+ d = time_sec(divisor) * BILLION + time_nsec(divisor);
+ assert(d != 0);
+ return (t / d);
+}
+
bool
time_update(struct timespec *time)
{
struct timespec old_time;
- memcpy(&old_time, time, sizeof(struct timespec));
+ assert(time_valid(time));
+
+ time_copy(&old_time, time);
#ifdef _WIN32
FILETIME ft;
@@ -27,10 +176,11 @@
#endif
/* Handle non-monotonic clocks. */
- if (unlikely(old_time.tv_sec > time->tv_sec))
+ if (unlikely(time_compare(&old_time, time) > 0)) {
+ time_copy(time, &old_time);
return (true);
- if (unlikely(old_time.tv_sec == time->tv_sec))
- return old_time.tv_nsec > time->tv_nsec;
+ }
+ assert(time_valid(time));
return (false);
}
diff --git a/test/include/test/jemalloc_test.h.in b/test/include/test/jemalloc_test.h.in
index 455569d..223162e 100644
--- a/test/include/test/jemalloc_test.h.in
+++ b/test/include/test/jemalloc_test.h.in
@@ -94,6 +94,7 @@
# define JEMALLOC_H_STRUCTS
# define JEMALLOC_H_EXTERNS
# define JEMALLOC_H_INLINES
+# include "jemalloc/internal/time.h"
# include "jemalloc/internal/util.h"
# include "jemalloc/internal/qr.h"
# include "jemalloc/internal/ql.h"
diff --git a/test/include/test/timer.h b/test/include/test/timer.h
index a7fefdf..a791f9c 100644
--- a/test/include/test/timer.h
+++ b/test/include/test/timer.h
@@ -3,21 +3,9 @@
#include <unistd.h>
#include <sys/time.h>
-#define JEMALLOC_CLOCK_GETTIME defined(_POSIX_MONOTONIC_CLOCK) \
- && _POSIX_MONOTONIC_CLOCK >= 0
-
typedef struct {
-#ifdef _WIN32
- FILETIME ft0;
- FILETIME ft1;
-#elif JEMALLOC_CLOCK_GETTIME
- struct timespec ts0;
- struct timespec ts1;
- int clock_id;
-#else
- struct timeval tv0;
- struct timeval tv1;
-#endif
+ struct timespec t0;
+ struct timespec t1;
} timedelta_t;
void timer_start(timedelta_t *timer);
diff --git a/test/src/timer.c b/test/src/timer.c
index 0c93aba..15306cf 100644
--- a/test/src/timer.c
+++ b/test/src/timer.c
@@ -4,50 +4,26 @@
timer_start(timedelta_t *timer)
{
-#ifdef _WIN32
- GetSystemTimeAsFileTime(&timer->ft0);
-#elif JEMALLOC_CLOCK_GETTIME
- if (sysconf(_SC_MONOTONIC_CLOCK) <= 0)
- timer->clock_id = CLOCK_REALTIME;
- else
- timer->clock_id = CLOCK_MONOTONIC;
- clock_gettime(timer->clock_id, &timer->ts0);
-#else
- gettimeofday(&timer->tv0, NULL);
-#endif
+ time_init(&timer->t0, 0, 0);
+ time_update(&timer->t0);
}
void
timer_stop(timedelta_t *timer)
{
-#ifdef _WIN32
- GetSystemTimeAsFileTime(&timer->ft0);
-#elif JEMALLOC_CLOCK_GETTIME
- clock_gettime(timer->clock_id, &timer->ts1);
-#else
- gettimeofday(&timer->tv1, NULL);
-#endif
+ time_copy(&timer->t1, &timer->t0);
+ time_update(&timer->t1);
}
uint64_t
timer_usec(const timedelta_t *timer)
{
+ struct timespec delta;
-#ifdef _WIN32
- uint64_t t0, t1;
- t0 = (((uint64_t)timer->ft0.dwHighDateTime) << 32) |
- timer->ft0.dwLowDateTime;
- t1 = (((uint64_t)timer->ft1.dwHighDateTime) << 32) |
- timer->ft1.dwLowDateTime;
- return ((t1 - t0) / 10);
-#elif JEMALLOC_CLOCK_GETTIME
- return (((timer->ts1.tv_sec - timer->ts0.tv_sec) * 1000000) +
- (timer->ts1.tv_nsec - timer->ts0.tv_nsec) / 1000);
-#else
- return (((timer->tv1.tv_sec - timer->tv0.tv_sec) * 1000000) +
- timer->tv1.tv_usec - timer->tv0.tv_usec);
-#endif
+ time_copy(&delta, &timer->t1);
+ time_subtract(&delta, &timer->t0);
+ return (time_sec(&delta) * 1000000 + time_nsec(&delta) / 1000);
}
void
diff --git a/test/unit/time.c b/test/unit/time.c
index 80460f9..941e6f1 100644
--- a/test/unit/time.c
+++ b/test/unit/time.c
@@ -1,16 +1,206 @@
#include "test/jemalloc_test.h"
+#define BILLION 1000000000
+
+TEST_BEGIN(test_time_init)
+{
+ struct timespec ts;
+
+ time_init(&ts, 42, 43);
+ assert_ld_eq(ts.tv_sec, 42, "tv_sec incorrectly initialized");
+ assert_ld_eq(ts.tv_nsec, 43, "tv_nsec incorrectly initialized");
+}
+TEST_END
+
+TEST_BEGIN(test_time_sec)
+{
+ struct timespec ts;
+
+ time_init(&ts, 42, 43);
+ assert_ld_eq(time_sec(&ts), 42, "tv_sec incorrectly read");
+}
+TEST_END
+
+TEST_BEGIN(test_time_nsec)
+{
+ struct timespec ts;
+
+ time_init(&ts, 42, 43);
+ assert_ld_eq(time_nsec(&ts), 43, "tv_nsec incorrectly read");
+}
+TEST_END
+
+TEST_BEGIN(test_time_copy)
+{
+ struct timespec tsa, tsb;
+
+ time_init(&tsa, 42, 43);
+ time_init(&tsb, 0, 0);
+ time_copy(&tsb, &tsa);
+ assert_ld_eq(time_sec(&tsb), 42, "tv_sec incorrectly copied");
+ assert_ld_eq(time_nsec(&tsb), 43, "tv_nsec incorrectly copied");
+}
+TEST_END
+
+TEST_BEGIN(test_time_compare)
+{
+ struct timespec tsa, tsb;
+
+ time_init(&tsa, 42, 43);
+ time_copy(&tsb, &tsa);
+ assert_d_eq(time_compare(&tsa, &tsb), 0, "Times should be equal");
+ assert_d_eq(time_compare(&tsb, &tsa), 0, "Times should be equal");
+
+ time_init(&tsb, 42, 42);
+ assert_d_eq(time_compare(&tsa, &tsb), 1,
+ "tsa should be greater than tsb");
+ assert_d_eq(time_compare(&tsb, &tsa), -1,
+ "tsb should be less than tsa");
+
+ time_init(&tsb, 42, 44);
+ assert_d_eq(time_compare(&tsa, &tsb), -1,
+ "tsa should be less than tsb");
+ assert_d_eq(time_compare(&tsb, &tsa), 1,
+ "tsb should be greater than tsa");
+
+ time_init(&tsb, 41, BILLION - 1);
+ assert_d_eq(time_compare(&tsa, &tsb), 1,
+ "tsa should be greater than tsb");
+ assert_d_eq(time_compare(&tsb, &tsa), -1,
+ "tsb should be less than tsa");
+
+ time_init(&tsb, 43, 0);
+ assert_d_eq(time_compare(&tsa, &tsb), -1,
+ "tsa should be less than tsb");
+ assert_d_eq(time_compare(&tsb, &tsa), 1,
+ "tsb should be greater than tsa");
+}
+TEST_END
+
+TEST_BEGIN(test_time_add)
+{
+ struct timespec tsa, tsb;
+
+ time_init(&tsa, 42, 43);
+ time_copy(&tsb, &tsa);
+ time_add(&tsa, &tsb);
+ time_init(&tsb, 84, 86);
+ assert_d_eq(time_compare(&tsa, &tsb), 0, "Incorrect addition result");
+
+ time_init(&tsa, 42, BILLION - 1);
+ time_copy(&tsb, &tsa);
+ time_add(&tsa, &tsb);
+ time_init(&tsb, 85, BILLION - 2);
+ assert_d_eq(time_compare(&tsa, &tsb), 0, "Incorrect addition result");
+}
+TEST_END
+
+TEST_BEGIN(test_time_subtract)
+{
+ struct timespec tsa, tsb;
+
+ time_init(&tsa, 42, 43);
+ time_copy(&tsb, &tsa);
+ time_subtract(&tsa, &tsb);
+ time_init(&tsb, 0, 0);
+ assert_d_eq(time_compare(&tsa, &tsb), 0,
+ "Incorrect subtraction result");
+
+ time_init(&tsa, 42, 43);
+ time_init(&tsb, 41, 44);
+ time_subtract(&tsa, &tsb);
+ time_init(&tsb, 0, BILLION - 1);
+ assert_d_eq(time_compare(&tsa, &tsb), 0,
+ "Incorrect subtraction result");
+}
+TEST_END
+
+TEST_BEGIN(test_time_imultiply)
+{
+ struct timespec tsa, tsb;
+
+ time_init(&tsa, 42, 43);
+ time_imultiply(&tsa, 10);
+ time_init(&tsb, 420, 430);
+ assert_d_eq(time_compare(&tsa, &tsb), 0,
+ "Incorrect multiplication result");
+
+ time_init(&tsa, 42, 666666666);
+ time_imultiply(&tsa, 3);
+ time_init(&tsb, 127, 999999998);
+ assert_d_eq(time_compare(&tsa, &tsb), 0,
+ "Incorrect multiplication result");
+}
+TEST_END
+
+TEST_BEGIN(test_time_idivide)
+{
+ struct timespec tsa, tsb;
+
+ time_init(&tsa, 42, 43);
+ time_copy(&tsb, &tsa);
+ time_imultiply(&tsa, 10);
+ time_idivide(&tsa, 10);
+ assert_d_eq(time_compare(&tsa, &tsb), 0, "Incorrect division result");
+
+ time_init(&tsa, 42, 666666666);
+ time_copy(&tsb, &tsa);
+ time_imultiply(&tsa, 3);
+ time_idivide(&tsa, 3);
+ assert_d_eq(time_compare(&tsa, &tsb), 0, "Incorrect division result");
+}
+TEST_END
+
+TEST_BEGIN(test_time_divide)
+{
+ struct timespec tsa, tsb, tsc;
+
+ time_init(&tsa, 42, 43);
+ time_copy(&tsb, &tsa);
+ time_imultiply(&tsa, 10);
+ assert_u64_eq(time_divide(&tsa, &tsb), 10,
+ "Incorrect division result");
+
+ time_init(&tsa, 42, 43);
+ time_copy(&tsb, &tsa);
+ time_imultiply(&tsa, 10);
+ time_init(&tsc, 0, 1);
+ time_add(&tsa, &tsc);
+ assert_u64_eq(time_divide(&tsa, &tsb), 10,
+ "Incorrect division result");
+
+ time_init(&tsa, 42, 43);
+ time_copy(&tsb, &tsa);
+ time_imultiply(&tsa, 10);
+ time_init(&tsc, 0, 1);
+ time_subtract(&tsa, &tsc);
+ assert_u64_eq(time_divide(&tsa, &tsb), 9, "Incorrect division result");
+}
+TEST_END
+
TEST_BEGIN(test_time_update)
{
struct timespec ts;
- memset(&ts, 0, sizeof(struct timespec));
+ time_init(&ts, 0, 0);
assert_false(time_update(&ts), "Basic time update failed.");
/* Only Rip Van Winkle sleeps this long. */
- ts.tv_sec += 631152000;
- assert_true(time_update(&ts), "Update should detect time roll-back.");
+ {
+ struct timespec addend;
+ time_init(&addend, 631152000, 0);
+ time_add(&ts, &addend);
+ }
+ {
+ struct timespec ts0;
+ time_copy(&ts0, &ts);
+ assert_true(time_update(&ts),
+ "Update should detect time roll-back.");
+ assert_d_eq(time_compare(&ts, &ts0), 0,
+ "Time should not have been modified");
+ }
+
}
TEST_END
@@ -19,5 +209,15 @@
{
return (test(
+ test_time_init,
+ test_time_sec,
+ test_time_nsec,
+ test_time_copy,
+ test_time_compare,
+ test_time_add,
+ test_time_subtract,
+ test_time_imultiply,
+ test_time_idivide,
+ test_time_divide,
test_time_update));
}