From d07319f790eb38c867bd04a23de674e2393825ff Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Sun, 22 Mar 2015 20:20:28 +0100 Subject: Better support for poor os monotonic sources --- erts/emulator/sys/unix/erl_unix_sys.h | 7 +- erts/emulator/sys/unix/sys_time.c | 200 ++++++++++------------------------ 2 files changed, 62 insertions(+), 145 deletions(-) (limited to 'erts/emulator/sys/unix') diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h index 5417bb2687..303ebeee7c 100644 --- a/erts/emulator/sys/unix/erl_unix_sys.h +++ b/erts/emulator/sys/unix/erl_unix_sys.h @@ -206,12 +206,9 @@ ErtsMonotonicTime erts_os_monotonic_time(void); || defined(OS_MONOTONIC_TIME_USING_TIMES) #if defined(OS_MONOTONIC_TIME_USING_TIMES) +/* Time unit determined at runtime... */ # undef ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT -# define ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT (1000*1000) -# define ERTS_HAVE_ERTS_OS_TIME_OFFSET_FINALIZE 1 -void erts_os_time_offset_finalize(void); -# define ERTS_HAVE_ERTS_OS_MONOTONIC_TIME_INIT -void erts_os_monotonic_time_init(void); +# define ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT 0 #endif ErtsMonotonicTime erts_os_monotonic_time(void); diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c index 9fdb1930b7..9db727b111 100644 --- a/erts/emulator/sys/unix/sys_time.c +++ b/erts/emulator/sys/unix/sys_time.c @@ -33,6 +33,7 @@ #include "sys.h" #include "global.h" +#include "erl_os_monotonic_time_extender.h" #ifdef NO_SYSCONF # define TICKS_PER_SEC() HZ @@ -55,36 +56,19 @@ #undef ERTS_SYS_TIME_INTERNAL_STATE_WRITE_FREQ__ #undef ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__ +#undef ERTS_SYS_TIME_INTERNAL_STATE_READ_MOSTLY__ #if defined(OS_MONOTONIC_TIME_USING_TIMES) -#define ERTS_WRAP_SYS_TIMES 1 -#define ERTS_SYS_TIME_INTERNAL_STATE_WRITE_FREQ__ -#define ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__ - -/* - * Not sure there is a need to use times() anymore, perhaps drop - * support for this soon... - * - * sys_times() might need to be wrapped and the values shifted (right) - * a bit to cope with faster ticks, this has to be taken care - * of dynamically to start with, a special version that uses - * the times() return value as a high resolution timer can be made - * to fully utilize the faster ticks, like on windows, but for now, we'll - * settle with this silly workaround - */ -#ifdef ERTS_WRAP_SYS_TIMES -static clock_t sys_times_wrap(void); -#define KERNEL_TICKS() (sys_times_wrap() & \ - ((1UL << ((sizeof(clock_t) * 8) - 1)) - 1)) -#define ERTS_KERNEL_TICK_TO_USEC(TCKS) (((TCKS)*(1000*1000)) \ - / internal_state.r.o.ticks_per_sec_wrap) -#else +static Uint32 +get_tick_count(void) +{ + struct tms unused; + return (Uint32) times(&unused); +} -#define KERNEL_TICKS() (sys_times(&internal_state.w.f.dummy_tms) & \ - ((1UL << ((sizeof(clock_t) * 8) - 1)) - 1)) -#define ERTS_KERNEL_TICK_TO_USEC(TCKS) (((TCKS)*(1000*1000))/SYS_CLK_TCK) -#endif +#define ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__ +#define ERTS_SYS_TIME_INTERNAL_STATE_READ_MOSTLY__ #endif @@ -109,8 +93,15 @@ ErtsMonotonicTime clock_gettime_monotonic_verified(void); #ifdef ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__ struct sys_time_internal_state_read_only__ { #if defined(OS_MONOTONIC_TIME_USING_TIMES) - int ticks_bsr; - int ticks_per_sec_wrap; + int times_shift; +#endif +}; +#endif + +#ifdef ERTS_SYS_TIME_INTERNAL_STATE_READ_MOSTLY__ +struct sys_time_internal_state_read_mostly__ { +#if defined(OS_MONOTONIC_TIME_USING_TIMES) + ErtsOsMonotonicTimeExtendState os_mtime_xtnd; #endif }; #endif @@ -121,15 +112,6 @@ struct sys_time_internal_state_write_freq__ { #if defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) ErtsMonotonicTime last_delivered; #endif -#if defined(OS_MONOTONIC_TIME_USING_TIMES) - ErtsMonotonicTime last_tick_count; - ErtsMonotonicTime last_tick_wrap_count; - ErtsMonotonicTime last_tick_monotonic_time; - ErtsMonotonicTime last_timeofday_usec; -#ifndef ERTS_WRAP_SYS_TIMES - SysTimes dummy_tms; -#endif -#endif }; #endif @@ -144,6 +126,14 @@ static struct { * ASSUMED_CACHE_LINE_SIZE]; } r; #endif +#ifdef ERTS_SYS_TIME_INTERNAL_STATE_READ_MOSTLY__ + union { + struct sys_time_internal_state_read_mostly__ m; + char align__[(((sizeof(struct sys_time_internal_state_read_mostly__) - 1) + / ASSUMED_CACHE_LINE_SIZE) + 1) + * ASSUMED_CACHE_LINE_SIZE]; + } wr; +#endif #ifdef ERTS_SYS_TIME_INTERNAL_STATE_WRITE_FREQ__ union { struct sys_time_internal_state_write_freq__ f; @@ -193,8 +183,6 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) init_resp->os_monotonic_info.func = "gethrtime"; #elif defined(OS_MONOTONIC_TIME_USING_TIMES) init_resp->os_monotonic_info.func = "times"; - init_resp->os_monotonic_info.locked_use = 1; - init_resp->os_monotonic_info.resolution = TICKS_PER_SEC(); #else # error Unknown erts_os_monotonic_time() implementation #endif @@ -247,7 +235,9 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) #endif /* defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) */ +#ifdef ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT init_resp->os_monotonic_time_unit = ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT; +#endif init_resp->sys_clock_resolution = SYS_CLOCK_RESOLUTION; /* @@ -258,38 +248,40 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) erl_exit(ERTS_ABORT_EXIT, "Can't get clock ticks/sec\n"); #if defined(OS_MONOTONIC_TIME_USING_TIMES) +#if ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT +# error Time unit is supposed to be determined at runtime... +#endif + { + ErtsMonotonicTime resolution = erts_sys_time_data__.r.o.ticks_per_sec; + ErtsMonotonicTime time_unit = resolution; + int shift = 0; - if (erts_sys_time_data__.r.o.ticks_per_sec >= 1000) { - /* Workaround for beta linux kernels, need to be done in runtime - to make erlang run on both 2.4 and 2.5 kernels. In the future, - the kernel ticks might as - well be used as a high res timer instead, but that's for when the - majority uses kernels with HZ == 1024 */ - internal_state.r.o.ticks_bsr = 3; - } else { - internal_state.r.o.ticks_bsr = 0; - } + while (time_unit < 1000*1000) { + time_unit <<= 1; + shift++; + } - internal_state.r.o.ticks_per_sec_wrap - = (erts_sys_time_data__.r.o.ticks_per_sec - >> internal_state.r.o.ticks_bsr); + init_resp->os_monotonic_info.resolution = resolution; + init_resp->os_monotonic_time_unit = time_unit; + init_resp->os_monotonic_info.extended = 1; + internal_state.r.o.times_shift = shift; - erts_smp_mtx_init(&internal_state.w.f.mtx, "os_monotonic_time"); - internal_state.w.f.last_tick_count = KERNEL_TICKS(); - internal_state.w.f.last_tick_wrap_count = 0; - internal_state.w.f.last_tick_monotonic_time - = ERTS_KERNEL_TICK_TO_USEC(internal_state.w.f.last_tick_count); - { - SysTimeval tv; - sys_gettimeofday(&tv); - internal_state.w.f.last_timeofday_usec = tv.tv_sec*(1000*1000); - internal_state.w.f.last_timeofday_usec += tv.tv_usec; + erts_init_os_monotonic_time_extender(&internal_state.wr.m.os_mtime_xtnd, + get_tick_count, + (1 << 29) / resolution); } - #endif /* defined(OS_MONOTONIC_TIME_USING_TIMES) */ } +void +erts_late_sys_init_time(void) +{ +#if defined(OS_MONOTONIC_TIME_USING_TIMES) + erts_late_init_os_monotonic_time_extender(&internal_state.wr.m.os_mtime_xtnd); +#endif +} + #if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) static ERTS_INLINE ErtsMonotonicTime @@ -379,86 +371,14 @@ ErtsMonotonicTime erts_os_monotonic_time(void) #elif defined(OS_MONOTONIC_TIME_USING_TIMES) -static clock_t sys_times_wrap(void) -{ - SysTimes dummy; - clock_t result = (sys_times(&dummy) >> internal_state.r.o.ticks_bsr); - return result; -} - -void -erts_os_time_offset_finalize(void) -{ - erts_smp_mtx_lock(&internal_state.w.f.mtx); - internal_state.w.f.last_tick_wrap_count = 0; - erts_smp_mtx_unlock(&internal_state.w.f.mtx); -} - -#define ERTS_TIME_EXCEED_TICK_LIMIT(SYS_TIME, TCK_TIME) \ - (((Uint64) (SYS_TIME)) - (((Uint64) (TCK_TIME)) \ - - ERTS_KERNEL_TICK_TO_USEC(1)) \ - > ERTS_KERNEL_TICK_TO_USEC(2)) - -/* Returns monotonic time in micro seconds */ ErtsMonotonicTime erts_os_monotonic_time(void) { - SysTimeval tv; - ErtsMonotonicTime res; - ErtsMonotonicTime tick_count; - ErtsMonotonicTime tick_count_usec; - ErtsMonotonicTime tick_monotonic_time; - ErtsMonotonicTime timeofday_usec; - ErtsMonotonicTime timeofday_diff_usec; - - erts_smp_mtx_lock(&internal_state.w.f.mtx); - - tick_count = (ErtsMonotonicTime) KERNEL_TICKS(); - sys_gettimeofday(&tv); - - if (internal_state.w.f.last_tick_count > tick_count) { - internal_state.w.f.last_tick_wrap_count - += (((ErtsMonotonicTime) 1) << ((sizeof(clock_t) * 8) - 1)); - } - internal_state.w.f.last_tick_count = tick_count; - tick_count += internal_state.w.f.last_tick_wrap_count; - - tick_count_usec = ERTS_KERNEL_TICK_TO_USEC(tick_count); - - timeofday_usec = (ErtsMonotonicTime) tv.tv_sec*(1000*1000); - timeofday_usec += (ErtsMonotonicTime) tv.tv_usec; - timeofday_diff_usec = timeofday_usec; - timeofday_diff_usec -= internal_state.w.f.last_timeofday_usec; - internal_state.w.f.last_timeofday_usec = timeofday_usec; - - if (timeofday_diff_usec < 0) { - /* timeofday jumped backwards use tick count only... */ - tick_monotonic_time = tick_count_usec; - } - else { - /* Use time diff from of timeofday if not off by too much... */ - tick_monotonic_time = internal_state.w.f.last_tick_monotonic_time; - tick_monotonic_time += timeofday_diff_usec; - - if (ERTS_TIME_EXCEED_TICK_LIMIT(tick_monotonic_time, tick_count_usec)) { - /* - * Value off by more than one tick from tick_count, i.e. - * timofday leaped one way or the other. We use - * tick_count_usec as is instead and unfortunately - * get lousy precision. - */ - tick_monotonic_time = tick_count_usec; - } - } - - if (internal_state.w.f.last_tick_monotonic_time < tick_monotonic_time) - internal_state.w.f.last_tick_monotonic_time = tick_monotonic_time; - - res = internal_state.w.f.last_tick_monotonic_time; - - erts_smp_mtx_unlock(&internal_state.w.f.mtx); - - return res; + Uint32 ticks = get_tick_count(); + ERTS_CHK_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd, + ticks); + return ERTS_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd, + ticks) << internal_state.r.o.times_shift; } #endif /* !defined(OS_MONOTONIC_TIME_USING_TIMES) */ -- cgit v1.2.3 From e52829ceb614b36c31a650dea455a463fc490698 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Mon, 23 Mar 2015 16:39:56 +0100 Subject: erts_sys_hrtime() for lcnt --- erts/emulator/sys/unix/erl_unix_sys.h | 12 ++++++++++ erts/emulator/sys/unix/sys.c | 12 +++++----- erts/emulator/sys/unix/sys_time.c | 44 +++++++++++++++++++++++++++++++---- 3 files changed, 57 insertions(+), 11 deletions(-) (limited to 'erts/emulator/sys/unix') diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h index 303ebeee7c..a14a4b3eae 100644 --- a/erts/emulator/sys/unix/erl_unix_sys.h +++ b/erts/emulator/sys/unix/erl_unix_sys.h @@ -161,8 +161,10 @@ typedef struct tms SysTimes; #if SIZEOF_LONG == 8 typedef long ErtsMonotonicTime; +typedef long ErtsSysHrTime; #elif SIZEOF_LONG_LONG == 8 typedef long long ErtsMonotonicTime; +typedef long long ErtsSysHrTime; #else #error No signed 64-bit type found... #endif @@ -201,6 +203,7 @@ ErtsMonotonicTime erts_os_monotonic_time(void); #elif defined(OS_MONOTONIC_TIME_USING_GETHRTIME) #define erts_os_monotonic() ((ErtsMonotonicTime) gethrtime()) +#define erts_sys_hrtime() ((ErtsSysHrTime) gethrtime()) #elif defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) \ || defined(OS_MONOTONIC_TIME_USING_TIMES) @@ -221,6 +224,15 @@ ErtsMonotonicTime erts_os_monotonic_time(void); #endif +/* + * erts_sys_hrtime() is the highest resolution + * time function found. Time unit is nano-seconds. + * It may or may not be monotonic. + */ +#ifndef erts_sys_hrtime +extern ErtsSysHrTime erts_sys_hrtime(void); +#endif + struct erts_sys_time_read_only_data__ { #ifdef ERTS_OS_MONOTONIC_INLINE_FUNC_PTR_CALL__ ErtsMonotonicTime (*os_monotonic_time)(void); diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index 58b01c094e..3647ea6a88 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -528,18 +528,18 @@ erts_sys_pre_init(void) erts_thr_init(&eid); -#endif /* USE_THREADS */ - - erts_init_sys_time_sup(); - -#ifdef USE_THREADS - report_exit_list = NULL; #ifdef ERTS_ENABLE_LOCK_COUNT erts_lcnt_init(); #endif +#endif /* USE_THREADS */ + + erts_init_sys_time_sup(); + +#ifdef USE_THREADS + #if CHLDWTHR || defined(ERTS_SMP) erts_mtx_init(&chld_stat_mtx, "child_status"); #endif diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c index 9db727b111..134e3a67b0 100644 --- a/erts/emulator/sys/unix/sys_time.c +++ b/erts/emulator/sys/unix/sys_time.c @@ -85,8 +85,8 @@ ErtsSysTimeData__ erts_sys_time_data__ erts_align_attribute(ERTS_CACHE_LINE_SIZE #define ERTS_SYS_TIME_INTERNAL_STATE_WRITE_FREQ__ -ErtsMonotonicTime clock_gettime_monotonic_raw(void); -ErtsMonotonicTime clock_gettime_monotonic_verified(void); +static ErtsMonotonicTime clock_gettime_monotonic_raw(void); +static ErtsMonotonicTime clock_gettime_monotonic_verified(void); #endif /* defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) */ @@ -306,7 +306,7 @@ clock_gettime_monotonic(void) #if defined(__linux__) -ErtsMonotonicTime clock_gettime_monotonic_verified(void) +static ErtsMonotonicTime clock_gettime_monotonic_verified(void) { ErtsMonotonicTime mtime; @@ -322,7 +322,7 @@ ErtsMonotonicTime clock_gettime_monotonic_verified(void) return mtime; } -ErtsMonotonicTime clock_gettime_monotonic_raw(void) +static ErtsMonotonicTime clock_gettime_monotonic_raw(void) { return clock_gettime_monotonic(); } @@ -336,6 +336,12 @@ ErtsMonotonicTime erts_os_monotonic_time(void) #endif /* !defined(__linux__) */ +ErtsSysHrTime +erts_sys_hrtime(void) +{ + return (ErtsSysHrTime) clock_gettime_monotonic(); +} + #elif defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) #include @@ -369,6 +375,12 @@ ErtsMonotonicTime erts_os_monotonic_time(void) return mtime; } +ErtsSysHrTime +erts_sys_hrtime(void) +{ + return (ErtsSysHrTime) erts_os_monotonic_time(); +} + #elif defined(OS_MONOTONIC_TIME_USING_TIMES) ErtsMonotonicTime @@ -381,7 +393,29 @@ erts_os_monotonic_time(void) ticks) << internal_state.r.o.times_shift; } -#endif /* !defined(OS_MONOTONIC_TIME_USING_TIMES) */ +# define ERTS_NEED_ERTS_SYS_HRTIME_FALLBACK + +#else /* !defined(OS_MONOTONIC_TIME_USING_TIMES) */ +/* No os-monotonic-time */ +# define ERTS_NEED_ERTS_SYS_HRTIME_FALLBACK +#endif + +#ifdef ERTS_NEED_ERTS_SYS_HRTIME_FALLBACK + +ErtsSysHrTime +erts_sys_hrtime(void) +{ + ErtsSysHrTime time; + struct timeval tv; + gettimeofday(&tv); + time = (ErtsSysHrTime) tv.tv_sec; + time *= (ErtsSysHrTime) 1000*1000*1000; + time += ((ErtsSysHrTime) tv.tv_usec)*1000; + return time; +} + +#endif + #ifdef HAVE_GETHRVTIME_PROCFS_IOCTL -- cgit v1.2.3 From c20482023b70768bd84d25f1e34dbbc2fe09cf31 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 24 Mar 2015 15:28:11 +0100 Subject: Better OS system time implementation --- erts/emulator/sys/unix/erl_unix_sys.h | 4 + erts/emulator/sys/unix/sys_time.c | 167 ++++++++++++++++++++++++++++++---- 2 files changed, 154 insertions(+), 17 deletions(-) (limited to 'erts/emulator/sys/unix') diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h index a14a4b3eae..5394e94c8c 100644 --- a/erts/emulator/sys/unix/erl_unix_sys.h +++ b/erts/emulator/sys/unix/erl_unix_sys.h @@ -169,6 +169,10 @@ typedef long long ErtsSysHrTime; #error No signed 64-bit type found... #endif +typedef ErtsMonotonicTime ErtsSystemTime; + +ErtsSystemTime erts_os_system_time(void); + #define ERTS_MONOTONIC_TIME_MIN (((ErtsMonotonicTime) 1) << 63) #define ERTS_MONOTONIC_TIME_MAX (~ERTS_MONOTONIC_TIME_MIN) diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c index 134e3a67b0..d6591a8296 100644 --- a/erts/emulator/sys/unix/sys_time.c +++ b/erts/emulator/sys/unix/sys_time.c @@ -150,44 +150,46 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) { #if !defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) - init_resp->have_os_monotonic = 0; + init_resp->have_os_monotonic_time = 0; #else /* defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) */ int major, minor, build, vsn; - init_resp->os_monotonic_info.resolution = (Uint64) 1000*1000*1000; + init_resp->os_monotonic_time_info.resolution = (Uint64) 1000*1000*1000; #if defined(HAVE_CLOCK_GETRES) && defined(MONOTONIC_CLOCK_ID) { struct timespec ts; - if (clock_getres(MONOTONIC_CLOCK_ID, &ts) == 0 - && ts.tv_sec == 0 && ts.tv_nsec != 0) { - init_resp->os_monotonic_info.resolution /= ts.tv_nsec; + if (clock_getres(MONOTONIC_CLOCK_ID, &ts) == 0) { + if (ts.tv_sec == 0 && ts.tv_nsec != 0) + init_resp->os_monotonic_time_info.resolution /= ts.tv_nsec; + else if (ts.tv_sec >= 1) + init_resp->os_monotonic_time_info.resolution = 1; } } #endif #ifdef MONOTONIC_CLOCK_ID_STR - init_resp->os_monotonic_info.clock_id = MONOTONIC_CLOCK_ID_STR; + init_resp->os_monotonic_time_info.clock_id = MONOTONIC_CLOCK_ID_STR; #else - init_resp->os_monotonic_info.clock_id = NULL; + init_resp->os_monotonic_time_info.clock_id = NULL; #endif - init_resp->os_monotonic_info.locked_use = 0; + init_resp->os_monotonic_time_info.locked_use = 0; #if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) - init_resp->os_monotonic_info.func = "clock_gettime"; + init_resp->os_monotonic_time_info.func = "clock_gettime"; #elif defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) - init_resp->os_monotonic_info.func = "clock_get_time"; + init_resp->os_monotonic_time_info.func = "clock_get_time"; #elif defined(OS_MONOTONIC_TIME_USING_GETHRTIME) - init_resp->os_monotonic_info.func = "gethrtime"; + init_resp->os_monotonic_time_info.func = "gethrtime"; #elif defined(OS_MONOTONIC_TIME_USING_TIMES) - init_resp->os_monotonic_info.func = "times"; + init_resp->os_monotonic_time_info.func = "times"; #else # error Unknown erts_os_monotonic_time() implementation #endif - init_resp->have_os_monotonic = 1; + init_resp->have_os_monotonic_time = 1; os_version(&major, &minor, &build); @@ -210,7 +212,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) "os_monotonic_time"); internal_state.w.f.last_delivered = clock_gettime_monotonic_raw(); - init_resp->os_monotonic_info.locked_use = 1; + init_resp->os_monotonic_time_info.locked_use = 1; } #else /* !(defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)) */ { @@ -227,7 +229,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF) if (sysconf(_SC_NPROCESSORS_CONF) > 1) #endif - init_resp->have_os_monotonic = 0; + init_resp->have_os_monotonic_time = 0; } } } @@ -261,9 +263,9 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) shift++; } - init_resp->os_monotonic_info.resolution = resolution; + init_resp->os_monotonic_time_info.resolution = resolution; init_resp->os_monotonic_time_unit = time_unit; - init_resp->os_monotonic_info.extended = 1; + init_resp->os_monotonic_time_info.extended = 1; internal_state.r.o.times_shift = shift; erts_init_os_monotonic_time_extender(&internal_state.wr.m.os_mtime_xtnd, @@ -272,6 +274,38 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) } #endif /* defined(OS_MONOTONIC_TIME_USING_TIMES) */ +#ifdef WALL_CLOCK_ID_STR + init_resp->os_system_time_info.clock_id = WALL_CLOCK_ID_STR; +#else + init_resp->os_system_time_info.clock_id = NULL; +#endif + + init_resp->os_system_time_info.locked_use = 0; + init_resp->os_system_time_info.resolution = (Uint64) 1000*1000*1000; +#if defined(HAVE_CLOCK_GETRES) && defined(WALL_CLOCK_ID) + { + struct timespec ts; + if (clock_getres(WALL_CLOCK_ID, &ts) == 0) { + if (ts.tv_sec == 0 && ts.tv_nsec != 0) + init_resp->os_system_time_info.resolution /= ts.tv_nsec; + else if (ts.tv_sec >= 1) + init_resp->os_system_time_info.resolution = 1; + } + } +#endif + +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) + init_resp->os_system_time_info.func = "clock_gettime"; +#elif defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) + init_resp->os_system_time_info.func = "clock_get_time"; +#elif defined(OS_SYSTEM_TIME_GETTIMEOFDAY) + init_resp->os_system_time_info.func = "gettimeofday"; + init_resp->os_system_time_info.resolution = 1000*1000; + init_resp->os_system_time_info.clock_id = NULL; +#else +# error Missing erts_os_system_time() implmenentation +#endif + } void @@ -282,6 +316,105 @@ erts_late_sys_init_time(void) #endif } +static ERTS_INLINE ErtsSystemTime +adj_stime_time_unit(ErtsSystemTime stime, Uint32 res) +{ + if (res == ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT) + return stime; + if (res == (Uint32) 1000*1000*1000 + && ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT == 1000*1000) + return stime/1000; + if (res == (Uint32) 1000*1000 + && ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT == 1000*1000*1000) + return stime*1000; + return ((ErtsSystemTime) + erts_time_unit_conversion(stime, + (Uint32) res, + (Uint32) ERTS_MONOTONIC_TIME_UNIT)); +} + +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) + +ErtsSystemTime +erts_os_system_time(void) +{ + ErtsSystemTime stime; + struct timespec ts; + + if (clock_gettime(WALL_CLOCK_ID,&ts) != 0) { + int err = errno; + char *errstr = err ? strerror(err) : "unknown"; + erl_exit(ERTS_ABORT_EXIT, + "clock_gettime(%s, _) failed: %s (%d)\n", + WALL_CLOCK_ID_STR, errstr, err); + + } + + stime = (ErtsSystemTime) ts.tv_sec; + stime *= (ErtsSystemTime) 1000*1000*1000; + stime += (ErtsSystemTime) ts.tv_nsec; + return adj_stime_time_unit(stime, (Uint32) 1000*1000*1000); +} + +#elif defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) + +ErtsSystemTime +erts_os_system_time(void) +{ + ErtsSystemTime stime; + kern_return_t res; + clock_serv_t clk_srv; + mach_timespec_t time_spec; + int err; + + host_get_clock_service(mach_host_self(), + WALL_CLOCK_ID, + &clk_srv); + errno = 0; + res = clock_get_time(clk_srv, &time_spec); + err = errno; + mach_port_deallocate(mach_task_self(), clk_srv); + if (res != KERN_SUCCESS) { + char *errstr = err ? strerror(err) : "unknown"; + erl_exit(ERTS_ABORT_EXIT, + "clock_get_time(%s, _) failed: %s (%d)\n", + MONOTONIC_CLOCK_ID_STR, errstr, err); + } + + stime = (ErtsSystemTime) time_spec.tv_sec; + stime *= (ErtsSystemTime) 1000*1000*1000; + stime += (ErtsSystemTime) time_spec.tv_nsec; + + return adj_stime_time_unit(stime, (Uint32) 1000*1000*1000); +} + +#elif defined(OS_SYSTEM_TIME_GETTIMEOFDAY) + +ErtsSystemTime +erts_os_system_time(void) +{ + ErtsSystemTime stime; + struct timeval tv; + + if (gettimeofday(&tv, NULL) != 0) { + int err = errno; + char *errstr = err ? strerror(err) : "unknown"; + erl_exit(ERTS_ABORT_EXIT, + "gettimeofday(_, NULL) failed: %s (%d)\n", + errstr, err); + } + + stime = (ErtsSystemTime) tv.tv_sec; + stime *= (ErtsSystemTime) 1000*1000; + stime += (ErtsSystemTime) tv.tv_usec; + + return adj_stime_time_unit(stime, (Uint32) 1000*1000); +} + +#else +# error Missing erts_os_system_time() implmenentation +#endif + #if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) static ERTS_INLINE ErtsMonotonicTime -- cgit v1.2.3