Flesh out time_*() API.

This commit is contained in:
Jason Evans 2016-02-19 12:35:37 -08:00
parent e5d5a4a517
commit 94451d184b
8 changed files with 397 additions and 56 deletions

View File

@ -116,7 +116,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/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 \

View File

@ -460,6 +460,18 @@ tcaches_get
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

View File

@ -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 */

View File

@ -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 @@ time_update(struct timespec *time)
#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);
}

View File

@ -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"

View File

@ -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);

View File

@ -4,50 +4,26 @@ void
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

View File

@ -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 @@ 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));
}