diff --git a/configure.ac b/configure.ac index 787ef1b0..d9fdebd7 100644 --- a/configure.ac +++ b/configure.ac @@ -1776,6 +1776,18 @@ if test "x${je_cv_mach_absolute_time}" = "xyes" ; then AC_DEFINE([JEMALLOC_HAVE_MACH_ABSOLUTE_TIME]) fi +dnl check for CLOCK_REALTIME (always should be available on Linux) +JE_COMPILABLE([clock_gettime(CLOCK_REALTIME, ...)], [ +#include +], [ + struct timespec ts; + + clock_gettime(CLOCK_REALTIME, &ts); +], [je_cv_clock_realtime]) +if test "x${je_cv_clock_realtime}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_CLOCK_REALTIME]) +fi + dnl Use syscall(2) (if available) by default. AC_ARG_ENABLE([syscall], [AS_HELP_STRING([--disable-syscall], [Disable use of syscall(2)])], diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index c442a219..83e733e3 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -100,6 +100,11 @@ */ #undef JEMALLOC_HAVE_MACH_ABSOLUTE_TIME +/* + * Defined if clock_gettime(CLOCK_REALTIME, ...) is available. + */ +#undef JEMALLOC_HAVE_CLOCK_REALTIME + /* * Defined if _malloc_thread_cleanup() exists. At least in the case of * FreeBSD, pthread_key_create() allocates, which if used during malloc diff --git a/include/jemalloc/internal/jemalloc_internal_externs.h b/include/jemalloc/internal/jemalloc_internal_externs.h index 338a590f..3dea1e21 100644 --- a/include/jemalloc/internal/jemalloc_internal_externs.h +++ b/include/jemalloc/internal/jemalloc_internal_externs.h @@ -3,6 +3,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/tsd_types.h" +#include "jemalloc/internal/nstime.h" /* TSD checks this to set thread local slow state accordingly. */ extern bool malloc_slow; diff --git a/include/jemalloc/internal/jemalloc_preamble.h.in b/include/jemalloc/internal/jemalloc_preamble.h.in index 3418cbfa..66302ab3 100644 --- a/include/jemalloc/internal/jemalloc_preamble.h.in +++ b/include/jemalloc/internal/jemalloc_preamble.h.in @@ -209,5 +209,12 @@ static const bool have_background_thread = false #endif ; +static const bool config_high_res_timer = +#ifdef JEMALLOC_HAVE_CLOCK_REALTIME + true +#else + false +#endif + ; #endif /* JEMALLOC_PREAMBLE_H */ diff --git a/include/jemalloc/internal/nstime.h b/include/jemalloc/internal/nstime.h index c4bee24d..76e4351a 100644 --- a/include/jemalloc/internal/nstime.h +++ b/include/jemalloc/internal/nstime.h @@ -30,10 +30,23 @@ uint64_t nstime_divide(const nstime_t *time, const nstime_t *divisor); typedef bool (nstime_monotonic_t)(void); extern nstime_monotonic_t *JET_MUTABLE nstime_monotonic; -typedef bool (nstime_update_t)(nstime_t *); +typedef void (nstime_update_t)(nstime_t *); extern nstime_update_t *JET_MUTABLE nstime_update; -bool nstime_init_update(nstime_t *time); +typedef void (nstime_prof_update_t)(nstime_t *); +extern nstime_prof_update_t *JET_MUTABLE nstime_prof_update; + +void nstime_init_update(nstime_t *time); +void nstime_prof_init_update(nstime_t *time); + +enum prof_time_res_e { + prof_time_res_default = 0, + prof_time_res_high = 1 +}; +typedef enum prof_time_res_e prof_time_res_t; + +extern prof_time_res_t opt_prof_time_res; +extern const char *prof_time_res_mode_names[]; JEMALLOC_ALWAYS_INLINE void nstime_init_zero(nstime_t *time) { diff --git a/src/ctl.c b/src/ctl.c index 0bd38feb..24d9eb34 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -129,6 +129,7 @@ CTL_PROTO(opt_prof_leak) CTL_PROTO(opt_prof_accum) CTL_PROTO(opt_prof_recent_alloc_max) CTL_PROTO(opt_prof_experimental_use_sys_thread_name) +CTL_PROTO(opt_prof_time_res) CTL_PROTO(opt_zero_realloc) CTL_PROTO(tcache_create) CTL_PROTO(tcache_flush) @@ -385,7 +386,8 @@ static const ctl_named_node_t opt_node[] = { {NAME("prof_recent_alloc_max"), CTL(opt_prof_recent_alloc_max)}, {NAME("prof_experimental_use_sys_thread_name"), CTL(opt_prof_experimental_use_sys_thread_name)}, - {NAME("zero_realloc"), CTL(opt_zero_realloc)} + {NAME("zero_realloc"), CTL(opt_zero_realloc)}, + {NAME("prof_time_resolution"), CTL(opt_prof_time_res)} }; static const ctl_named_node_t tcache_node[] = { @@ -1853,6 +1855,8 @@ CTL_RO_NL_CGEN(config_prof, opt_prof_recent_alloc_max, opt_prof_recent_alloc_max, ssize_t) CTL_RO_NL_CGEN(config_prof, opt_prof_experimental_use_sys_thread_name, opt_prof_experimental_use_sys_thread_name, bool) +CTL_RO_NL_CGEN(config_prof, opt_prof_time_res, + prof_time_res_mode_names[opt_prof_time_res], const char *) CTL_RO_NL_GEN(opt_zero_realloc, zero_realloc_mode_names[opt_zero_realloc_action], const char *) diff --git a/src/jemalloc.c b/src/jemalloc.c index 74355d40..bb1b38cb 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -14,6 +14,7 @@ #include "jemalloc/internal/log.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/nstime.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/safety_check.h" #include "jemalloc/internal/sc.h" @@ -1497,6 +1498,26 @@ malloc_conf_init_helper(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS], CONF_HANDLE_BOOL( opt_prof_experimental_use_sys_thread_name, "prof_experimental_use_sys_thread_name") + if (CONF_MATCH("prof_time_resolution")) { + if (CONF_MATCH_VALUE("default")) { + opt_prof_time_res = + prof_time_res_default; + } else if (CONF_MATCH_VALUE("high")) { + if (!config_high_res_timer) { + CONF_ERROR( + "No high resolution" + " timer support", + k, klen, v, vlen); + } else { + opt_prof_time_res = + prof_time_res_high; + } + } else { + CONF_ERROR("Invalid conf value", + k, klen, v, vlen); + } + } + CONF_CONTINUE; } if (config_log) { if (CONF_MATCH("log")) { diff --git a/src/large.c b/src/large.c index b8439371..cc3e727c 100644 --- a/src/large.c +++ b/src/large.c @@ -305,7 +305,7 @@ large_prof_tctx_reset(edata_t *edata) { void large_prof_info_set(edata_t *edata, prof_tctx_t *tctx) { nstime_t t; - nstime_init_update(&t); + nstime_prof_init_update(&t); edata_prof_alloc_time_set(edata, &t); edata_prof_recent_alloc_init(edata); large_prof_tctx_set(edata, tctx); diff --git a/src/nstime.c b/src/nstime.c index eb8f6c0a..184aa4c9 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -152,25 +152,65 @@ nstime_monotonic_impl(void) { } nstime_monotonic_t *JET_MUTABLE nstime_monotonic = nstime_monotonic_impl; -static bool +prof_time_res_t opt_prof_time_res = + prof_time_res_default; + +const char *prof_time_res_mode_names[] = { + "default", + "high", +}; + + +static void +nstime_get_realtime(nstime_t *time) { +#if defined(JEMALLOC_HAVE_CLOCK_REALTIME) && !defined(_WIN32) + struct timespec ts; + + clock_gettime(CLOCK_REALTIME, &ts); + nstime_init2(time, ts.tv_sec, ts.tv_nsec); +#else + unreachable(); +#endif +} + +static void +nstime_prof_update_impl(nstime_t *time) { + nstime_t old_time; + + nstime_copy(&old_time, time); + + if (opt_prof_time_res == prof_time_res_high) { + nstime_get_realtime(time); + } else { + nstime_get(time); + } +} +nstime_prof_update_t *JET_MUTABLE nstime_prof_update = nstime_prof_update_impl; + +static void nstime_update_impl(nstime_t *time) { nstime_t old_time; nstime_copy(&old_time, time); - nstime_get(time); + nstime_get(time); /* Handle non-monotonic clocks. */ if (unlikely(nstime_compare(&old_time, time) > 0)) { nstime_copy(time, &old_time); - return true; } - - return false; } nstime_update_t *JET_MUTABLE nstime_update = nstime_update_impl; -bool +void nstime_init_update(nstime_t *time) { nstime_init_zero(time); - return nstime_update(time); + nstime_update(time); } + +void +nstime_prof_init_update(nstime_t *time) { + nstime_init_zero(time); + nstime_prof_update(time); +} + + diff --git a/src/prof_log.c b/src/prof_log.c index 1635979e..7fea8548 100644 --- a/src/prof_log.c +++ b/src/prof_log.c @@ -235,7 +235,7 @@ prof_try_log(tsd_t *tsd, size_t usize, prof_info_t *prof_info) { nstime_t alloc_time = prof_info->alloc_time; nstime_t free_time; - nstime_init_update(&free_time); + nstime_prof_init_update(&free_time); size_t sz = sizeof(prof_alloc_node_t); prof_alloc_node_t *new_node = (prof_alloc_node_t *) @@ -572,6 +572,11 @@ prof_log_emit_metadata(emitter_t *emitter) { emitter_json_kv(emitter, "lg_sample_rate", emitter_type_int, &lg_prof_sample); + const char *res_type = + prof_time_res_mode_names[opt_prof_time_res]; + emitter_json_kv(emitter, "prof_time_resolution", + emitter_type_string, &res_type); + int pid = prof_getpid(); emitter_json_kv(emitter, "pid", emitter_type_int, &pid); diff --git a/src/prof_recent.c b/src/prof_recent.c index 949ae76b..270691ac 100644 --- a/src/prof_recent.c +++ b/src/prof_recent.c @@ -219,7 +219,7 @@ prof_recent_alloc_reset(tsd_t *tsd, edata_t *edata) { assert(nstime_equals_zero(&recent->dalloc_time)); assert(recent->dalloc_tctx == NULL); if (dalloc_tctx != NULL) { - nstime_update(&recent->dalloc_time); + nstime_prof_update(&recent->dalloc_time); recent->dalloc_tctx = dalloc_tctx; dalloc_tctx = NULL; } diff --git a/test/unit/arena_decay.c b/test/unit/arena_decay.c index 7ed270f4..86f7057d 100644 --- a/test/unit/arena_decay.c +++ b/test/unit/arena_decay.c @@ -26,13 +26,12 @@ nstime_monotonic_mock(void) { return monotonic_mock; } -static bool +static void nstime_update_mock(nstime_t *time) { nupdates_mock++; if (monotonic_mock) { nstime_copy(time, &time_mock); } - return !monotonic_mock; } static unsigned diff --git a/test/unit/nstime.c b/test/unit/nstime.c index bf875017..083002bd 100644 --- a/test/unit/nstime.c +++ b/test/unit/nstime.c @@ -206,28 +206,6 @@ TEST_BEGIN(test_nstime_monotonic) { } TEST_END -TEST_BEGIN(test_nstime_update) { - nstime_t nst; - - expect_false(nstime_init_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); - expect_true(nstime_update(&nst), - "Update should detect time roll-back."); - expect_d_eq(nstime_compare(&nst, &nst0), 0, - "Time should not have been modified"); - } -} -TEST_END - int main(void) { return test( @@ -242,6 +220,5 @@ main(void) { test_nstime_imultiply, test_nstime_idivide, test_nstime_divide, - test_nstime_monotonic, - test_nstime_update); + test_nstime_monotonic); }