diff options
author | Rickard Green <[email protected]> | 2015-03-24 16:56:08 +0100 |
---|---|---|
committer | Rickard Green <[email protected]> | 2015-03-24 16:56:08 +0100 |
commit | 5345727d647ea65b7a0417c87b94cf958ef9ee13 (patch) | |
tree | bcc1c75102741e9768c88b1481390e40e32586e7 /erts/emulator/sys/win32 | |
parent | a11cec66e37c039d33091db056c0ae44405043ac (diff) | |
parent | c20482023b70768bd84d25f1e34dbbc2fe09cf31 (diff) | |
download | otp-5345727d647ea65b7a0417c87b94cf958ef9ee13.tar.gz otp-5345727d647ea65b7a0417c87b94cf958ef9ee13.tar.bz2 otp-5345727d647ea65b7a0417c87b94cf958ef9ee13.zip |
Merge branch 'rickard/time_api/OTP-11997'
* rickard/time_api/OTP-11997:
Better OS system time implementation
Documentation adjustments
Fix zero timout timers
erts_sys_hrtime() for lcnt
Better support for poor os monotonic sources
Conflicts:
erts/preloaded/ebin/erlang.beam
Diffstat (limited to 'erts/emulator/sys/win32')
-rw-r--r-- | erts/emulator/sys/win32/erl_win_sys.h | 14 | ||||
-rw-r--r-- | erts/emulator/sys/win32/sys_time.c | 185 |
2 files changed, 164 insertions, 35 deletions
diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h index 33aa88ab5f..9aeb460720 100644 --- a/erts/emulator/sys/win32/erl_win_sys.h +++ b/erts/emulator/sys/win32/erl_win_sys.h @@ -172,13 +172,19 @@ typedef long long Sint64; # endif typedef long long ErtsMonotonicTime; +typedef long long ErtsSysHrTime; #else typedef ULONGLONG Uint64; typedef LONGLONG Sint64; typedef LONGLONG ErtsMonotonicTime; +typedef LONGLONG ErtsSysHrTime; #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) @@ -187,6 +193,7 @@ typedef LONGLONG ErtsMonotonicTime; struct erts_sys_time_read_only_data__ { ErtsMonotonicTime (*os_monotonic_time)(void); + ErtsSysHrTime (*sys_hrtime)(void); }; typedef struct { @@ -201,6 +208,7 @@ typedef struct { extern ErtsSysTimeData__ erts_sys_time_data__; ERTS_GLB_INLINE ErtsMonotonicTime erts_os_monotonic_time(void); +ERTS_GLB_INLINE ErtsSysHrTime erts_sys_hrtime(void); #if ERTS_GLB_INLINE_INCL_FUNC_DEF @@ -210,6 +218,12 @@ erts_os_monotonic_time(void) return (*erts_sys_time_data__.r.o.os_monotonic_time)(); } +ERTS_GLB_INLINE ErtsSysHrTime +erts_sys_hrtime(void) +{ + return (*erts_sys_time_data__.r.o.sys_hrtime)(); +} + #endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ extern void sys_gettimeofday(SysTimeval *tv); diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c index 3a10125c81..da9c4d2e29 100644 --- a/erts/emulator/sys/win32/sys_time.c +++ b/erts/emulator/sys/win32/sys_time.c @@ -25,6 +25,8 @@ #endif #include "sys.h" #include "assert.h" +#include "erl_os_monotonic_time_extender.h" +#include "erl_time.h" #define LL_LITERAL(X) ERTS_I64_LITERAL(X) @@ -71,6 +73,8 @@ static int days_in_month[2][13] = { {0,31,28,31,30,31,30,31,31,30,31,30,31}, {0,31,29,31,30,31,30,31,31,30,31,30,31}}; +#define ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT 10 + /* * erts_os_monotonic_time() */ @@ -78,6 +82,12 @@ static int days_in_month[2][13] = { struct sys_time_internal_state_read_only__ { ULONGLONG (WINAPI *pGetTickCount64)(void); BOOL (WINAPI *pQueryPerformanceCounter)(LARGE_INTEGER *); + Sint32 pcf; + int using_get_tick_count_time_unit; +}; + +struct sys_time_internal_state_read_mostly__ { + ErtsOsMonotonicTimeExtendState os_mtime_xtnd; }; struct sys_time_internal_state_write_freq__ { @@ -94,6 +104,12 @@ __declspec(align(ASSUMED_CACHE_LINE_SIZE)) struct { * ASSUMED_CACHE_LINE_SIZE]; } r; 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; + union { struct sys_time_internal_state_write_freq__ f; char align__[(((sizeof(struct sys_time_internal_state_write_freq__) - 1) / ASSUMED_CACHE_LINE_SIZE) + 1) @@ -114,29 +130,63 @@ os_monotonic_time_qpc(void) return (ErtsMonotonicTime) pc.QuadPart; } +static Uint32 +get_tick_count(void) +{ + return (Uint32) GetTickCount(); +} + static ErtsMonotonicTime os_monotonic_time_gtc32(void) { - ULONGLONG res, ticks; + Uint32 ticks = (Uint32) GetTickCount(); + ERTS_CHK_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd, + tick_count); + return ERTS_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd, + ticks) << 10; +} - erts_smp_mtx_lock(&internal_state.w.f.mtime_mtx); +static ErtsMonotonicTime +os_monotonic_time_gtc64(void) +{ + ULONGLONG ticks = (*internal_state.r.o.pGetTickCount64)(); + return (ErtsMonotonicTime) ticks << 10; +} - ticks = (ULONGLONG) (GetTickCount() & 0x7FFFFFFF); - if (ticks < internal_state.w.f.last_tick_count) - internal_state.w.f.wrap += (ULONGLONG) LL_LITERAL(1) << 31; - internal_state.w.f.last_tick_count = ticks; - res = ticks + internal_state.w.f.wrap; +static ErtsSysHrTime +sys_hrtime_qpc(void) +{ + LARGE_INTEGER pc; - erts_smp_mtx_unlock(&internal_state.w.f.mtime_mtx); + if (!(*internal_state.r.o.pQueryPerformanceCounter)(&pc)) + erl_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); - return (ErtsMonotonicTime) res*1000; + ASSERT(pc.QuadPart > 0); + + return (ErtsSysHrTime) erts_time_unit_conversion((Uint64) pc.QuadPart, + internal_state.r.o.pcf, + (Uint32) 1000*1000*1000); } -static ErtsMonotonicTime -os_monotonic_time_gtc64(void) +static ErtsSysHrTime +sys_hrtime_gtc32(void) { - ULONGLONG ticks = (*internal_state.r.o.pGetTickCount64)(); - return (ErtsMonotonicTime) ticks*1000; + ErtsSysHrTime time; + Uint32 ticks = (Uint32) GetTickCount(); + ERTS_CHK_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd, + tick_count); + time = (ErtsSysHrTime) ERTS_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd, + ticks); + time *= (ErtsSysHrTime) (1000 * 1000); + return time; +} + +static ErtsSysHrTime +sys_hrtime_gtc64(void) +{ + ErtsSysHrTime time = (*internal_state.r.o.pGetTickCount64)(); + time *= (ErtsSysHrTime) (1000*1000); + return time; } /* @@ -147,11 +197,12 @@ void sys_init_time(ErtsSysInitTimeResult *init_resp) { ErtsMonotonicTime (*os_mtime_func)(void); + ErtsSysHrTime (*sys_hrtime_func)(void) = NULL; ErtsMonotonicTime time_unit; char kernel_dll_name[] = "kernel32"; HMODULE module; - init_resp->os_monotonic_info.clock_id = NULL; + init_resp->os_monotonic_time_info.clock_id = NULL; module = GetModuleHandle(kernel_dll_name); if (!module) { @@ -161,11 +212,20 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) internal_state.w.f.wrap = 0; internal_state.w.f.last_tick_count = 0; - init_resp->os_monotonic_info.func = "GetTickCount"; - init_resp->os_monotonic_info.locked_use = 1; - init_resp->os_monotonic_info.resolution = 1000; - time_unit = (ErtsMonotonicTime) 1000*1000; + init_resp->os_monotonic_time_info.func = "GetTickCount"; + init_resp->os_monotonic_time_info.locked_use = 1; + /* 10-16 ms resolution according to MicroSoft documentation */ + init_resp->os_monotonic_time_info.resolution = 100; /* 10 ms */ + time_unit = (ErtsMonotonicTime) 1000; + time_unit <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; + internal_state.r.o.using_get_tick_count_time_unit = 1; os_mtime_func = os_monotonic_time_gtc32; + init_resp->os_monotonic_time_info.extended = 1; + erts_init_os_monotonic_time_extender(&internal_state.wr.m.os_mtime_xtnd, + get_tick_count, + 60*60*24*7); /* Check once a week */ + if (!sys_hrtime_func) + sys_hrtime_func = sys_hrtime_gtc32; } else { int major, minor, build; @@ -182,11 +242,16 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) if (!internal_state.r.o.pGetTickCount64) goto get_tick_count; - init_resp->os_monotonic_info.func = "GetTickCount64"; - init_resp->os_monotonic_info.locked_use = 0; - init_resp->os_monotonic_info.resolution = 1000; - time_unit = (ErtsMonotonicTime) 1000*1000; + init_resp->os_monotonic_time_info.func = "GetTickCount64"; + init_resp->os_monotonic_time_info.locked_use = 0; + /* 10-16 ms resolution according to MicroSoft documentation */ + init_resp->os_monotonic_time_info.resolution = 100; /* 10 ms */ + time_unit = (ErtsMonotonicTime) 1000; + time_unit <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; + internal_state.r.o.using_get_tick_count_time_unit = 1; os_mtime_func = os_monotonic_time_gtc64; + if (!sys_hrtime_func) + sys_hrtime_func = sys_hrtime_gtc64; } else { /* Vista or newer... */ @@ -199,40 +264,59 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) goto get_tick_count64; if (!(*QPF)(&pf)) goto get_tick_count64; - /* - * We only use QueryPerformanceCounter() if - * its frequency is equal to, or larger than - * GHz in order to ensure that the user wont - * be able to observe faulty order between - * values retrieved on different threads. - */ - if (pf.QuadPart < (LONGLONG) 1000*1000*1000) - goto get_tick_count64; + internal_state.r.o.pQueryPerformanceCounter = ((BOOL (WINAPI *)(LARGE_INTEGER *)) GetProcAddress(module, "QueryPerformanceCounter")); if (!internal_state.r.o.pQueryPerformanceCounter) goto get_tick_count64; - init_resp->os_monotonic_info.func = "QueryPerformanceCounter"; - init_resp->os_monotonic_info.locked_use = 0; + if (pf.QuadPart < (((LONGLONG) 1) << 32)) { + internal_state.r.o.pcf = (Uint32) pf.QuadPart; + sys_hrtime_func = sys_hrtime_qpc; + } + + /* + * We only use QueryPerformanceCounter() for + * os-monotonic-time if its frequency is equal + * to, or larger than GHz in order to ensure + * that the user wont be able to observe faulty + * order between values retrieved on different threads. + */ + if (pf.QuadPart < (LONGLONG) 1000*1000*1000) + goto get_tick_count64; + + init_resp->os_monotonic_time_info.func = "QueryPerformanceCounter"; + init_resp->os_monotonic_time_info.locked_use = 0; time_unit = (ErtsMonotonicTime) pf.QuadPart; - init_resp->os_monotonic_info.resolution = time_unit; + internal_state.r.o.using_get_tick_count_time_unit = 0; + init_resp->os_monotonic_time_info.resolution = time_unit; os_mtime_func = os_monotonic_time_qpc; } } erts_sys_time_data__.r.o.os_monotonic_time = os_mtime_func; init_resp->os_monotonic_time_unit = time_unit; - init_resp->have_os_monotonic = 1; + init_resp->have_os_monotonic_time = 1; init_resp->sys_clock_resolution = 1; + init_resp->os_system_time_info.func = "GetSystemTime"; + init_resp->os_system_time_info.clock_id = NULL; + init_resp->os_system_time_info.resolution = 100; + init_resp->os_system_time_info.locked_use = 0; + if(GetTimeZoneInformation(&static_tzi) && static_tzi.StandardDate.wMonth != 0 && static_tzi.DaylightDate.wMonth != 0) { have_static_tzi = 1; } +} +void +erts_late_sys_init_time(void) +{ + if (erts_sys_time_data__.r.o.os_monotonic_time == os_monotonic_time_gtc32) + erts_late_init_os_monotonic_time_extender(&internal_state.wr.m.os_mtime_xtnd); } /* Returns a switchtimes for DST as UTC filetimes given data from a @@ -513,6 +597,37 @@ sys_gettimeofday(SysTimeval *tv) EPOCH_JULIAN_DIFF); } +ErtsSystemTime +erts_os_system_time(void) +{ + SYSTEMTIME t; + FILETIME ft; + ULARGE_INTEGER ull; + ErtsSystemTime stime; + + GetSystemTime(&t); + SystemTimeToFileTime(&t, &ft); + FILETIME_TO_ULI(ull,ft); + + /* now in 100 ns units */ + + stime = (ErtsSystemTime) ull.QuadPart; + stime -= (((ErtsSystemTime) EPOCH_JULIAN_DIFF) + * ((ErtsSystemTime) (10*1000*1000))); + stime /= (ErtsSystemTime) (10*1000); + + if (internal_state.r.o.using_get_tick_count_time_unit) { + stime <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; + return stime; + } + + return ((ErtsSystemTime) + erts_time_unit_conversion(stime, + (Uint32) 1000, + (Uint32) ERTS_MONOTONIC_TIME_UNIT)); +} + + clock_t sys_times(SysTimes *buffer) { clock_t kernel_ticks = (GetTickCount() / |