From 9bad07903962962de9f656d281b9b1e7e9501c87 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 21 Feb 2016 11:25:02 -0800 Subject: [PATCH] Refactor time_* into nstime_*. Use a single uint64_t in nstime_t to store nanoseconds rather than using struct timespec. This reduces fragility around conversions between long and uint64_t, especially missing casts that only cause problems on 32-bit platforms. --- Makefile.in | 38 ++- include/jemalloc/internal/arena.h | 6 +- .../jemalloc/internal/jemalloc_internal.h.in | 8 +- include/jemalloc/internal/nstime.h | 48 ++++ include/jemalloc/internal/private_symbols.txt | 24 +- include/jemalloc/internal/time.h | 41 ---- src/arena.c | 53 ++--- src/jemalloc.c | 2 +- src/nstime.c | 148 ++++++++++++ src/time.c | 198 ---------------- test/include/test/jemalloc_test.h.in | 2 +- test/include/test/timer.h | 4 +- test/src/timer.c | 16 +- test/unit/decay.c | 48 ++-- test/unit/mallctl.c | 4 +- test/unit/nstime.c | 220 +++++++++++++++++ test/unit/time.c | 223 ------------------ 17 files changed, 526 insertions(+), 557 deletions(-) create mode 100644 include/jemalloc/internal/nstime.h delete mode 100644 include/jemalloc/internal/time.h create mode 100644 src/nstime.c delete mode 100644 src/time.c create mode 100644 test/unit/nstime.c delete mode 100644 test/unit/time.c diff --git a/Makefile.in b/Makefile.in index e5681926..a4555c03 100644 --- a/Makefile.in +++ b/Makefile.in @@ -78,15 +78,31 @@ LIBJEMALLOC := $(LIBPREFIX)jemalloc$(install_suffix) # Lists of files. BINS := $(objroot)bin/jemalloc-config $(objroot)bin/jemalloc.sh $(objroot)bin/jeprof C_HDRS := $(objroot)include/jemalloc/jemalloc$(install_suffix).h -C_SRCS := $(srcroot)src/jemalloc.c $(srcroot)src/arena.c \ - $(srcroot)src/atomic.c $(srcroot)src/base.c $(srcroot)src/bitmap.c \ - $(srcroot)src/chunk.c $(srcroot)src/chunk_dss.c \ - $(srcroot)src/chunk_mmap.c $(srcroot)src/ckh.c $(srcroot)src/ctl.c \ - $(srcroot)src/extent.c $(srcroot)src/hash.c $(srcroot)src/huge.c \ - $(srcroot)src/mb.c $(srcroot)src/mutex.c $(srcroot)src/pages.c \ - $(srcroot)src/prng.c $(srcroot)src/prof.c $(srcroot)src/quarantine.c \ - $(srcroot)src/rtree.c $(srcroot)src/stats.c $(srcroot)src/tcache.c \ - $(srcroot)src/ticker.c $(srcroot)src/time.c $(srcroot)src/tsd.c \ +C_SRCS := $(srcroot)src/jemalloc.c \ + $(srcroot)src/arena.c \ + $(srcroot)src/atomic.c \ + $(srcroot)src/base.c \ + $(srcroot)src/bitmap.c \ + $(srcroot)src/chunk.c \ + $(srcroot)src/chunk_dss.c \ + $(srcroot)src/chunk_mmap.c \ + $(srcroot)src/ckh.c \ + $(srcroot)src/ctl.c \ + $(srcroot)src/extent.c \ + $(srcroot)src/hash.c \ + $(srcroot)src/huge.c \ + $(srcroot)src/mb.c \ + $(srcroot)src/mutex.c \ + $(srcroot)src/nstime.c \ + $(srcroot)src/pages.c \ + $(srcroot)src/prng.c \ + $(srcroot)src/prof.c \ + $(srcroot)src/quarantine.c \ + $(srcroot)src/rtree.c \ + $(srcroot)src/stats.c \ + $(srcroot)src/tcache.c \ + $(srcroot)src/ticker.c \ + $(srcroot)src/tsd.c \ $(srcroot)src/util.c ifeq ($(enable_valgrind), 1) C_SRCS += $(srcroot)src/valgrind.c @@ -117,7 +133,7 @@ C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \ $(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/time.c $(srcroot)src/util.c +C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c TESTS_UNIT := $(srcroot)test/unit/atomic.c \ $(srcroot)test/unit/bitmap.c \ $(srcroot)test/unit/ckh.c \ @@ -148,7 +164,7 @@ TESTS_UNIT := $(srcroot)test/unit/atomic.c \ $(srcroot)test/unit/smoothstep.c \ $(srcroot)test/unit/stats.c \ $(srcroot)test/unit/ticker.c \ - $(srcroot)test/unit/time.c \ + $(srcroot)test/unit/nstime.c \ $(srcroot)test/unit/tsd.c \ $(srcroot)test/unit/util.c \ $(srcroot)test/unit/zero.c diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 76d3be19..65d4158b 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -395,7 +395,7 @@ struct arena_s { */ ssize_t decay_time; /* decay_time / SMOOTHSTEP_NSTEPS. */ - struct timespec decay_interval; + nstime_t decay_interval; /* * Time at which the current decay interval logically started. We do * not actually advance to a new epoch until sometime after it starts @@ -403,7 +403,7 @@ struct arena_s { * to completely skip epochs. In all cases, during epoch advancement we * merge all relevant activity into the most recently recorded epoch. */ - struct timespec decay_epoch; + nstime_t decay_epoch; /* decay_deadline randomness generator. */ uint64_t decay_jitter_state; /* @@ -413,7 +413,7 @@ struct arena_s { * decay_interval, but we randomize the deadline to reduce the * likelihood of arenas purging in lockstep. */ - struct timespec decay_deadline; + nstime_t decay_deadline; /* * Number of dirty pages at beginning of current epoch. During epoch * advancement we use the delta between decay_ndirty and ndirty to diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index aa97d7c7..0260b9a8 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -356,7 +356,7 @@ typedef unsigned szind_t; # define VARIABLE_ARRAY(type, name, count) type name[(count)] #endif -#include "jemalloc/internal/time.h" +#include "jemalloc/internal/nstime.h" #include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" @@ -387,7 +387,7 @@ typedef unsigned szind_t; /******************************************************************************/ #define JEMALLOC_H_STRUCTS -#include "jemalloc/internal/time.h" +#include "jemalloc/internal/nstime.h" #include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" @@ -477,7 +477,7 @@ void jemalloc_prefork(void); void jemalloc_postfork_parent(void); void jemalloc_postfork_child(void); -#include "jemalloc/internal/time.h" +#include "jemalloc/internal/nstime.h" #include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" @@ -508,7 +508,7 @@ void jemalloc_postfork_child(void); /******************************************************************************/ #define JEMALLOC_H_INLINES -#include "jemalloc/internal/time.h" +#include "jemalloc/internal/nstime.h" #include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" diff --git a/include/jemalloc/internal/nstime.h b/include/jemalloc/internal/nstime.h new file mode 100644 index 00000000..bd04f04b --- /dev/null +++ b/include/jemalloc/internal/nstime.h @@ -0,0 +1,48 @@ +/******************************************************************************/ +#ifdef JEMALLOC_H_TYPES + +#define JEMALLOC_CLOCK_GETTIME defined(_POSIX_MONOTONIC_CLOCK) \ + && _POSIX_MONOTONIC_CLOCK >= 0 + +typedef struct nstime_s nstime_t; + +/* Maximum supported number of seconds (~584 years). */ +#define NSTIME_SEC_MAX 18446744072 + +#endif /* JEMALLOC_H_TYPES */ +/******************************************************************************/ +#ifdef JEMALLOC_H_STRUCTS + +struct nstime_s { + uint64_t ns; +}; + +#endif /* JEMALLOC_H_STRUCTS */ +/******************************************************************************/ +#ifdef JEMALLOC_H_EXTERNS + +void nstime_init(nstime_t *time, uint64_t ns); +void nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec); +uint64_t nstime_ns(const nstime_t *time); +uint64_t nstime_sec(const nstime_t *time); +uint64_t nstime_nsec(const nstime_t *time); +void nstime_copy(nstime_t *time, const nstime_t *source); +int nstime_compare(const nstime_t *a, const nstime_t *b); +void nstime_add(nstime_t *time, const nstime_t *addend); +void nstime_subtract(nstime_t *time, const nstime_t *subtrahend); +void nstime_imultiply(nstime_t *time, uint64_t multiplier); +void nstime_idivide(nstime_t *time, uint64_t divisor); +uint64_t nstime_divide(const nstime_t *time, const nstime_t *divisor); +#ifdef JEMALLOC_JET +typedef bool (nstime_update_t)(nstime_t *); +extern nstime_update_t *nstime_update; +#else +bool nstime_update(nstime_t *time); +#endif + +#endif /* JEMALLOC_H_EXTERNS */ +/******************************************************************************/ +#ifdef JEMALLOC_H_INLINES + +#endif /* JEMALLOC_H_INLINES */ +/******************************************************************************/ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 8428cf48..c12baadb 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -327,6 +327,19 @@ narenas_tdata_cleanup narenas_total_get ncpus nhbins +nstime_add +nstime_compare +nstime_copy +nstime_divide +nstime_idivide +nstime_imultiply +nstime_init +nstime_init2 +nstime_ns +nstime_nsec +nstime_sec +nstime_subtract +nstime_update opt_abort opt_decay_time opt_dss @@ -484,17 +497,6 @@ ticker_init ticker_read ticker_tick ticker_ticks -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 tsd_boot diff --git a/include/jemalloc/internal/time.h b/include/jemalloc/internal/time.h deleted file mode 100644 index dd1dd5bd..00000000 --- a/include/jemalloc/internal/time.h +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -#define JEMALLOC_CLOCK_GETTIME defined(_POSIX_MONOTONIC_CLOCK) \ - && _POSIX_MONOTONIC_CLOCK >= 0 - -/* Maximum supported number of seconds (~584 years). */ -#define TIME_SEC_MAX 18446744072 - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#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); -#ifdef JEMALLOC_JET -typedef bool (time_update_t)(struct timespec *); -extern time_update_t *time_update; -#else -bool time_update(struct timespec *time); -#endif - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/src/arena.c b/src/arena.c index b1078ae9..77c691a1 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1224,27 +1224,24 @@ arena_decay_deadline_init(arena_t *arena) * Generate a new deadline that is uniformly random within the next * epoch after the current one. */ - time_copy(&arena->decay_deadline, &arena->decay_epoch); - time_add(&arena->decay_deadline, &arena->decay_interval); + nstime_copy(&arena->decay_deadline, &arena->decay_epoch); + nstime_add(&arena->decay_deadline, &arena->decay_interval); if (arena->decay_time > 0) { - uint64_t decay_interval_ns, r; - struct timespec jitter; + nstime_t jitter; - decay_interval_ns = time_sec(&arena->decay_interval) * - 1000000000 + time_nsec(&arena->decay_interval); - r = prng_range(&arena->decay_jitter_state, decay_interval_ns); - time_init(&jitter, r / 1000000000, r % 1000000000); - time_add(&arena->decay_deadline, &jitter); + nstime_init(&jitter, prng_range(&arena->decay_jitter_state, + nstime_ns(&arena->decay_interval))); + nstime_add(&arena->decay_deadline, &jitter); } } static bool -arena_decay_deadline_reached(const arena_t *arena, const struct timespec *time) +arena_decay_deadline_reached(const arena_t *arena, const nstime_t *time) { assert(opt_purge == purge_mode_decay); - return (time_compare(&arena->decay_deadline, time) <= 0); + return (nstime_compare(&arena->decay_deadline, time) <= 0); } static size_t @@ -1276,24 +1273,24 @@ arena_decay_backlog_npages_limit(const arena_t *arena) } static void -arena_decay_epoch_advance(arena_t *arena, const struct timespec *time) +arena_decay_epoch_advance(arena_t *arena, const nstime_t *time) { uint64_t nadvance; - struct timespec delta; + nstime_t delta; size_t ndirty_delta; assert(opt_purge == purge_mode_decay); assert(arena_decay_deadline_reached(arena, time)); - time_copy(&delta, time); - time_subtract(&delta, &arena->decay_epoch); - nadvance = time_divide(&delta, &arena->decay_interval); + nstime_copy(&delta, time); + nstime_subtract(&delta, &arena->decay_epoch); + nadvance = nstime_divide(&delta, &arena->decay_interval); assert(nadvance > 0); /* Add nadvance decay intervals to epoch. */ - time_copy(&delta, &arena->decay_interval); - time_imultiply(&delta, nadvance); - time_add(&arena->decay_epoch, &delta); + nstime_copy(&delta, &arena->decay_interval); + nstime_imultiply(&delta, nadvance); + nstime_add(&arena->decay_epoch, &delta); /* Set a new deadline. */ arena_decay_deadline_init(arena); @@ -1340,12 +1337,12 @@ arena_decay_init(arena_t *arena, ssize_t decay_time) arena->decay_time = decay_time; if (decay_time > 0) { - time_init(&arena->decay_interval, decay_time, 0); - time_idivide(&arena->decay_interval, SMOOTHSTEP_NSTEPS); + nstime_init2(&arena->decay_interval, decay_time, 0); + nstime_idivide(&arena->decay_interval, SMOOTHSTEP_NSTEPS); } - time_init(&arena->decay_epoch, 0, 0); - time_update(&arena->decay_epoch); + nstime_init(&arena->decay_epoch, 0); + nstime_update(&arena->decay_epoch); arena->decay_jitter_state = (uint64_t)(uintptr_t)arena; arena_decay_deadline_init(arena); arena->decay_ndirty = arena->ndirty; @@ -1357,7 +1354,7 @@ static bool arena_decay_time_valid(ssize_t decay_time) { - return (decay_time >= -1 && decay_time <= TIME_SEC_MAX); + return (decay_time >= -1 && decay_time <= NSTIME_SEC_MAX); } ssize_t @@ -1426,7 +1423,7 @@ arena_maybe_purge_ratio(arena_t *arena) static void arena_maybe_purge_decay(arena_t *arena) { - struct timespec time; + nstime_t time; size_t ndirty_limit; assert(opt_purge == purge_mode_decay); @@ -1438,10 +1435,10 @@ arena_maybe_purge_decay(arena_t *arena) return; } - time_copy(&time, &arena->decay_epoch); - if (unlikely(time_update(&time))) { + nstime_copy(&time, &arena->decay_epoch); + if (unlikely(nstime_update(&time))) { /* Time went backwards. Force an epoch advance. */ - time_copy(&time, &arena->decay_deadline); + nstime_copy(&time, &arena->decay_deadline); } if (arena_decay_deadline_reached(arena, &time)) diff --git a/src/jemalloc.c b/src/jemalloc.c index f69d951b..76b4f154 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1151,7 +1151,7 @@ malloc_conf_init(void) CONF_HANDLE_SSIZE_T(opt_lg_dirty_mult, "lg_dirty_mult", -1, (sizeof(size_t) << 3) - 1) CONF_HANDLE_SSIZE_T(opt_decay_time, "decay_time", -1, - TIME_SEC_MAX); + NSTIME_SEC_MAX); CONF_HANDLE_BOOL(opt_stats_print, "stats_print", true) if (config_fill) { if (CONF_MATCH("junk")) { diff --git a/src/nstime.c b/src/nstime.c new file mode 100644 index 00000000..4cf90b58 --- /dev/null +++ b/src/nstime.c @@ -0,0 +1,148 @@ +#include "jemalloc/internal/jemalloc_internal.h" + +#define BILLION UINT64_C(1000000000) + +void +nstime_init(nstime_t *time, uint64_t ns) +{ + + time->ns = ns; +} + +void +nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec) +{ + + time->ns = sec * BILLION + nsec; +} + +uint64_t +nstime_ns(const nstime_t *time) +{ + + return (time->ns); +} + +uint64_t +nstime_sec(const nstime_t *time) +{ + + return (time->ns / BILLION); +} + +uint64_t +nstime_nsec(const nstime_t *time) +{ + + return (time->ns % BILLION); +} + +void +nstime_copy(nstime_t *time, const nstime_t *source) +{ + + *time = *source; +} + +int +nstime_compare(const nstime_t *a, const nstime_t *b) +{ + + return ((a->ns > b->ns) - (a->ns < b->ns)); +} + +void +nstime_add(nstime_t *time, const nstime_t *addend) +{ + + assert(UINT64_MAX - time->ns >= addend->ns); + + time->ns += addend->ns; +} + +void +nstime_subtract(nstime_t *time, const nstime_t *subtrahend) +{ + + assert(nstime_compare(time, subtrahend) >= 0); + + time->ns -= subtrahend->ns; +} + +void +nstime_imultiply(nstime_t *time, uint64_t multiplier) +{ + + assert((((time->ns | multiplier) & (UINT64_MAX << (sizeof(uint64_t) << + 2))) == 0) || ((time->ns * multiplier) / multiplier == time->ns)); + + time->ns *= multiplier; +} + +void +nstime_idivide(nstime_t *time, uint64_t divisor) +{ + + assert(divisor != 0); + + time->ns /= divisor; +} + +uint64_t +nstime_divide(const nstime_t *time, const nstime_t *divisor) +{ + + assert(divisor->ns != 0); + + return (time->ns / divisor->ns); +} + +#ifdef JEMALLOC_JET +#undef nstime_update +#define nstime_update JEMALLOC_N(nstime_update_impl) +#endif +bool +nstime_update(nstime_t *time) +{ + nstime_t old_time; + + nstime_copy(&old_time, time); + +#ifdef _WIN32 + { + FILETIME ft; + uint64_t ticks; + GetSystemTimeAsFileTime(&ft); + ticks = (((uint64_t)ft.dwHighDateTime) << 32) | + ft.dwLowDateTime; + time->ns = ticks * 100; + } +#elif JEMALLOC_CLOCK_GETTIME + { + struct timespec ts; + + if (sysconf(_SC_MONOTONIC_CLOCK) > 0) + clock_gettime(CLOCK_MONOTONIC, &ts); + else + clock_gettime(CLOCK_REALTIME, &ts); + time->ns = ts.tv_sec * BILLION + ts.tv_nsec; + } +#else + struct timeval tv; + gettimeofday(&tv, NULL); + time->ns = tv.tv_sec * BILLION + tv.tv_usec * 1000; +#endif + + /* Handle non-monotonic clocks. */ + if (unlikely(nstime_compare(&old_time, time) > 0)) { + nstime_copy(time, &old_time); + return (true); + } + + return (false); +} +#ifdef JEMALLOC_JET +#undef nstime_update +#define nstime_update JEMALLOC_N(nstime_update) +nstime_update_t *nstime_update = JEMALLOC_N(nstime_update_impl); +#endif diff --git a/src/time.c b/src/time.c deleted file mode 100644 index 8205c61b..00000000 --- a/src/time.c +++ /dev/null @@ -1,198 +0,0 @@ -#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); -} - -#ifdef JEMALLOC_JET -#undef time_update -#define time_update JEMALLOC_N(time_update_impl) -#endif -bool -time_update(struct timespec *time) -{ - struct timespec old_time; - - assert(time_valid(time)); - - time_copy(&old_time, time); - -#ifdef _WIN32 - { - FILETIME ft; - uint64_t ticks; - GetSystemTimeAsFileTime(&ft); - ticks = (((uint64_t)ft.dwHighDateTime) << 32) | - ft.dwLowDateTime; - time->tv_sec = ticks / 10000000; - time->tv_nsec = ((ticks % 10000000) * 100); - } -#elif JEMALLOC_CLOCK_GETTIME - if (sysconf(_SC_MONOTONIC_CLOCK) > 0) - clock_gettime(CLOCK_MONOTONIC, time); - else - clock_gettime(CLOCK_REALTIME, time); -#else - struct timeval tv; - gettimeofday(&tv, NULL); - time->tv_sec = tv.tv_sec; - time->tv_nsec = tv.tv_usec * 1000; -#endif - - /* Handle non-monotonic clocks. */ - if (unlikely(time_compare(&old_time, time) > 0)) { - time_copy(time, &old_time); - return (true); - } - - assert(time_valid(time)); - return (false); -} -#ifdef JEMALLOC_JET -#undef time_update -#define time_update JEMALLOC_N(time_update) -time_update_t *time_update = JEMALLOC_N(time_update_impl); -#endif diff --git a/test/include/test/jemalloc_test.h.in b/test/include/test/jemalloc_test.h.in index 223162e1..4aaaf952 100644 --- a/test/include/test/jemalloc_test.h.in +++ b/test/include/test/jemalloc_test.h.in @@ -94,7 +94,7 @@ # define JEMALLOC_H_STRUCTS # define JEMALLOC_H_EXTERNS # define JEMALLOC_H_INLINES -# include "jemalloc/internal/time.h" +# include "jemalloc/internal/nstime.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 a791f9ce..0b27e019 100644 --- a/test/include/test/timer.h +++ b/test/include/test/timer.h @@ -4,8 +4,8 @@ #include typedef struct { - struct timespec t0; - struct timespec t1; + nstime_t t0; + nstime_t t1; } timedelta_t; void timer_start(timedelta_t *timer); diff --git a/test/src/timer.c b/test/src/timer.c index 15306cfd..e91b3cf2 100644 --- a/test/src/timer.c +++ b/test/src/timer.c @@ -4,26 +4,26 @@ void timer_start(timedelta_t *timer) { - time_init(&timer->t0, 0, 0); - time_update(&timer->t0); + nstime_init(&timer->t0, 0); + nstime_update(&timer->t0); } void timer_stop(timedelta_t *timer) { - time_copy(&timer->t1, &timer->t0); - time_update(&timer->t1); + nstime_copy(&timer->t1, &timer->t0); + nstime_update(&timer->t1); } uint64_t timer_usec(const timedelta_t *timer) { - struct timespec delta; + nstime_t delta; - time_copy(&delta, &timer->t1); - time_subtract(&delta, &timer->t0); - return (time_sec(&delta) * 1000000 + time_nsec(&delta) / 1000); + nstime_copy(&delta, &timer->t1); + nstime_subtract(&delta, &timer->t0); + return (nstime_ns(&delta) / 1000); } void diff --git a/test/unit/decay.c b/test/unit/decay.c index 20730de4..66d54dc8 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -2,19 +2,19 @@ const char *malloc_conf = "purge:decay,decay_time:1"; -static time_update_t *time_update_orig; +static nstime_update_t *nstime_update_orig; static unsigned nupdates_mock; -static struct timespec time_mock; +static nstime_t time_mock; static bool nonmonotonic_mock; static bool -time_update_mock(struct timespec *time) +nstime_update_mock(nstime_t *time) { nupdates_mock++; if (!nonmonotonic_mock) - time_copy(time, &time_mock); + nstime_copy(time, &time_mock); return (nonmonotonic_mock); } @@ -204,7 +204,7 @@ TEST_BEGIN(test_decay_ticker) uint64_t epoch, npurge0, npurge1; size_t sz, tcache_max, large; unsigned i, nupdates0; - struct timespec time, decay_time, deadline; + nstime_t time, decay_time, deadline; test_skip_if(opt_purge != purge_mode_decay); @@ -233,12 +233,12 @@ TEST_BEGIN(test_decay_ticker) } nupdates_mock = 0; - time_init(&time_mock, 0, 0); - time_update(&time_mock); + nstime_init(&time_mock, 0); + nstime_update(&time_mock); nonmonotonic_mock = false; - time_update_orig = time_update; - time_update = time_update_mock; + nstime_update_orig = nstime_update; + nstime_update = nstime_update_mock; for (i = 0; i < NPS; i++) { dallocx(ps[i], flags); @@ -246,16 +246,16 @@ TEST_BEGIN(test_decay_ticker) assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0, "Unexpected arena.0.decay failure"); assert_u_gt(nupdates_mock, nupdates0, - "Expected time_update() to be called"); + "Expected nstime_update() to be called"); } - time_update = time_update_orig; + nstime_update = nstime_update_orig; - time_init(&time, 0, 0); - time_update(&time); - time_init(&decay_time, opt_decay_time, 0); - time_copy(&deadline, &time); - time_add(&deadline, &decay_time); + nstime_init(&time, 0); + nstime_update(&time); + nstime_init2(&decay_time, opt_decay_time, 0); + nstime_copy(&deadline, &time); + nstime_add(&deadline, &decay_time); do { for (i = 0; i < DECAY_NTICKS_PER_UPDATE / 2; i++) { void *p = mallocx(1, flags); @@ -268,8 +268,8 @@ TEST_BEGIN(test_decay_ticker) assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge1, &sz, NULL, 0), 0, "Unexpected mallctl failure"); - time_update(&time); - } while (time_compare(&time, &deadline) <= 0 && npurge1 == npurge0); + nstime_update(&time); + } while (nstime_compare(&time, &deadline) <= 0 && npurge1 == npurge0); assert_u64_gt(npurge1, npurge0, "Expected purging to occur"); #undef NPS @@ -300,12 +300,12 @@ TEST_BEGIN(test_decay_nonmonotonic) "Unexpected mallctl failure"); nupdates_mock = 0; - time_init(&time_mock, 0, 0); - time_update(&time_mock); + nstime_init(&time_mock, 0); + nstime_update(&time_mock); nonmonotonic_mock = true; - time_update_orig = time_update; - time_update = time_update_mock; + nstime_update_orig = nstime_update; + nstime_update = nstime_update_mock; for (i = 0; i < NPS; i++) { ps[i] = mallocx(large0, flags); @@ -318,7 +318,7 @@ TEST_BEGIN(test_decay_nonmonotonic) assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0, "Unexpected arena.0.decay failure"); assert_u_gt(nupdates_mock, nupdates0, - "Expected time_update() to be called"); + "Expected nstime_update() to be called"); } assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(uint64_t)), 0, @@ -329,7 +329,7 @@ TEST_BEGIN(test_decay_nonmonotonic) assert_u64_gt(npurge1, npurge0, "Expected purging to occur"); - time_update = time_update_orig; + nstime_update = nstime_update_orig; #undef NPS } TEST_END diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index b312fc64..e8dc4926 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -401,7 +401,7 @@ TEST_BEGIN(test_arena_i_decay_time) &decay_time, sizeof(ssize_t)), EFAULT, "Unexpected mallctl() success"); - decay_time = TIME_SEC_MAX; + decay_time = 0x7fffffff; assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL, &decay_time, sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); @@ -567,7 +567,7 @@ TEST_BEGIN(test_arenas_decay_time) &decay_time, sizeof(ssize_t)), EFAULT, "Unexpected mallctl() success"); - decay_time = TIME_SEC_MAX; + decay_time = 0x7fffffff; assert_d_eq(mallctl("arenas.decay_time", NULL, NULL, &decay_time, sizeof(ssize_t)), 0, "Expected mallctl() failure"); diff --git a/test/unit/nstime.c b/test/unit/nstime.c new file mode 100644 index 00000000..cd7d9a6d --- /dev/null +++ b/test/unit/nstime.c @@ -0,0 +1,220 @@ +#include "test/jemalloc_test.h" + +#define BILLION UINT64_C(1000000000) + +TEST_BEGIN(test_nstime_init) +{ + nstime_t nst; + + nstime_init(&nst, 42000000043); + assert_u64_eq(nstime_ns(&nst), 42000000043, "ns incorrectly read"); + assert_u64_eq(nstime_sec(&nst), 42, "sec incorrectly read"); + assert_u64_eq(nstime_nsec(&nst), 43, "nsec incorrectly read"); +} +TEST_END + +TEST_BEGIN(test_nstime_init2) +{ + nstime_t nst; + + nstime_init2(&nst, 42, 43); + assert_u64_eq(nstime_sec(&nst), 42, "sec incorrectly read"); + assert_u64_eq(nstime_nsec(&nst), 43, "nsec incorrectly read"); +} +TEST_END + +TEST_BEGIN(test_nstime_copy) +{ + nstime_t nsta, nstb; + + nstime_init2(&nsta, 42, 43); + nstime_init(&nstb, 0); + nstime_copy(&nstb, &nsta); + assert_u64_eq(nstime_sec(&nstb), 42, "sec incorrectly copied"); + assert_u64_eq(nstime_nsec(&nstb), 43, "nsec incorrectly copied"); +} +TEST_END + +TEST_BEGIN(test_nstime_compare) +{ + nstime_t nsta, nstb; + + nstime_init2(&nsta, 42, 43); + nstime_copy(&nstb, &nsta); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, "Times should be equal"); + assert_d_eq(nstime_compare(&nstb, &nsta), 0, "Times should be equal"); + + nstime_init2(&nstb, 42, 42); + assert_d_eq(nstime_compare(&nsta, &nstb), 1, + "nsta should be greater than nstb"); + assert_d_eq(nstime_compare(&nstb, &nsta), -1, + "nstb should be less than nsta"); + + nstime_init2(&nstb, 42, 44); + assert_d_eq(nstime_compare(&nsta, &nstb), -1, + "nsta should be less than nstb"); + assert_d_eq(nstime_compare(&nstb, &nsta), 1, + "nstb should be greater than nsta"); + + nstime_init2(&nstb, 41, BILLION - 1); + assert_d_eq(nstime_compare(&nsta, &nstb), 1, + "nsta should be greater than nstb"); + assert_d_eq(nstime_compare(&nstb, &nsta), -1, + "nstb should be less than nsta"); + + nstime_init2(&nstb, 43, 0); + assert_d_eq(nstime_compare(&nsta, &nstb), -1, + "nsta should be less than nstb"); + assert_d_eq(nstime_compare(&nstb, &nsta), 1, + "nstb should be greater than nsta"); +} +TEST_END + +TEST_BEGIN(test_nstime_add) +{ + nstime_t nsta, nstb; + + nstime_init2(&nsta, 42, 43); + nstime_copy(&nstb, &nsta); + nstime_add(&nsta, &nstb); + nstime_init2(&nstb, 84, 86); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect addition result"); + + nstime_init2(&nsta, 42, BILLION - 1); + nstime_copy(&nstb, &nsta); + nstime_add(&nsta, &nstb); + nstime_init2(&nstb, 85, BILLION - 2); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect addition result"); +} +TEST_END + +TEST_BEGIN(test_nstime_subtract) +{ + nstime_t nsta, nstb; + + nstime_init2(&nsta, 42, 43); + nstime_copy(&nstb, &nsta); + nstime_subtract(&nsta, &nstb); + nstime_init(&nstb, 0); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect subtraction result"); + + nstime_init2(&nsta, 42, 43); + nstime_init2(&nstb, 41, 44); + nstime_subtract(&nsta, &nstb); + nstime_init2(&nstb, 0, BILLION - 1); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect subtraction result"); +} +TEST_END + +TEST_BEGIN(test_nstime_imultiply) +{ + nstime_t nsta, nstb; + + nstime_init2(&nsta, 42, 43); + nstime_imultiply(&nsta, 10); + nstime_init2(&nstb, 420, 430); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect multiplication result"); + + nstime_init2(&nsta, 42, 666666666); + nstime_imultiply(&nsta, 3); + nstime_init2(&nstb, 127, 999999998); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect multiplication result"); +} +TEST_END + +TEST_BEGIN(test_nstime_idivide) +{ + nstime_t nsta, nstb; + + nstime_init2(&nsta, 42, 43); + nstime_copy(&nstb, &nsta); + nstime_imultiply(&nsta, 10); + nstime_idivide(&nsta, 10); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect division result"); + + nstime_init2(&nsta, 42, 666666666); + nstime_copy(&nstb, &nsta); + nstime_imultiply(&nsta, 3); + nstime_idivide(&nsta, 3); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect division result"); +} +TEST_END + +TEST_BEGIN(test_nstime_divide) +{ + nstime_t nsta, nstb, nstc; + + nstime_init2(&nsta, 42, 43); + nstime_copy(&nstb, &nsta); + nstime_imultiply(&nsta, 10); + assert_u64_eq(nstime_divide(&nsta, &nstb), 10, + "Incorrect division result"); + + nstime_init2(&nsta, 42, 43); + nstime_copy(&nstb, &nsta); + nstime_imultiply(&nsta, 10); + nstime_init(&nstc, 1); + nstime_add(&nsta, &nstc); + assert_u64_eq(nstime_divide(&nsta, &nstb), 10, + "Incorrect division result"); + + nstime_init2(&nsta, 42, 43); + nstime_copy(&nstb, &nsta); + nstime_imultiply(&nsta, 10); + nstime_init(&nstc, 1); + nstime_subtract(&nsta, &nstc); + assert_u64_eq(nstime_divide(&nsta, &nstb), 9, + "Incorrect division result"); +} +TEST_END + +TEST_BEGIN(test_nstime_update) +{ + nstime_t nst; + + nstime_init(&nst, 0); + + assert_false(nstime_update(&nst), "Basic time update failed."); + + /* Only Rip Van Winkle sleeps this long. */ + { + nstime_t addend; + nstime_init2(&addend, 631152000, 0); + nstime_add(&nst, &addend); + } + { + nstime_t nst0; + nstime_copy(&nst0, &nst); + assert_true(nstime_update(&nst), + "Update should detect time roll-back."); + assert_d_eq(nstime_compare(&nst, &nst0), 0, + "Time should not have been modified"); + } + +} +TEST_END + +int +main(void) +{ + + return (test( + test_nstime_init, + test_nstime_init2, + test_nstime_copy, + test_nstime_compare, + test_nstime_add, + test_nstime_subtract, + test_nstime_imultiply, + test_nstime_idivide, + test_nstime_divide, + test_nstime_update)); +} diff --git a/test/unit/time.c b/test/unit/time.c deleted file mode 100644 index 941e6f13..00000000 --- a/test/unit/time.c +++ /dev/null @@ -1,223 +0,0 @@ -#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; - - time_init(&ts, 0, 0); - - assert_false(time_update(&ts), "Basic time update failed."); - - /* Only Rip Van Winkle sleeps this long. */ - { - 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 - -int -main(void) -{ - - 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)); -}