Flesh out time_*() API.
This commit is contained in:
parent
e5d5a4a517
commit
94451d184b
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
158
src/time.c
158
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 @@ 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);
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
206
test/unit/time.c
206
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 @@ 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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user