Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix retrieval of OS monotonic time on Windows #8343

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions erts/doc/src/erlang.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10247,6 +10247,18 @@ Metadata = #{ pid => pid(),
however, know that the precision is not better than
<c>OsMonotonicTimeResolution</c>.</p>
</item>
<tag><c>{used_resolution, UsedOsMonotonicTimeResolution}</c></tag>
<item><p>
The OS monotonic time resolution used by the runtime system.
This is very often the same as <c>OsMonotonicTimeResolution</c>.
However, on some systems the resolution has to be reduced in
order to reliably produce monotonic timestamps. An example of
this is when <c>QueryPerformanceCounter()</c> is used as
OS monotonic time source on Windows. If such a reduction of
the resolution has been done,
<c>UsedOsMonotonicTimeResolution</c> will be smaller than
<c>OsMonotonicTimeResolution</c>.
</p></item>
<tag><c>{extended, Extended}</c></tag>
<item><p><c>Extended</c> equals <c>yes</c> if
the range of time values has been extended;
Expand Down
13 changes: 11 additions & 2 deletions erts/emulator/beam/erl_time_sup.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ struct time_sup_read_only__ {
char *os_monotonic_time_clock_id;
int os_monotonic_time_locked;
Uint64 os_monotonic_time_resolution;
Uint64 os_monotonic_time_used_resolution;
Uint64 os_monotonic_time_extended;
#endif
char *os_system_time_func;
Expand Down Expand Up @@ -934,6 +935,10 @@ void erts_init_sys_time_sup(void)
= sys_init_time_res.os_monotonic_time_info.locked_use;
time_sup.r.o.os_monotonic_time_resolution
= sys_init_time_res.os_monotonic_time_info.resolution;
time_sup.r.o.os_monotonic_time_used_resolution
= (!sys_init_time_res.os_monotonic_time_info.used_resolution
? sys_init_time_res.os_monotonic_time_info.resolution
: sys_init_time_res.os_monotonic_time_info.used_resolution);
time_sup.r.o.os_monotonic_time_extended
= sys_init_time_res.os_monotonic_time_info.extended;
#endif
Expand Down Expand Up @@ -2044,8 +2049,8 @@ bld_monotonic_time_source(Uint **hpp, Uint *szp, Sint64 os_mtime)
return NIL;
#else
int i = 0;
Eterm k[6];
Eterm v[6];
Eterm k[7];
Eterm v[7];

if (time_sup.r.o.os_monotonic_time_disable)
return NIL;
Expand All @@ -2064,6 +2069,10 @@ bld_monotonic_time_source(Uint **hpp, Uint *szp, Sint64 os_mtime)
v[i++] = erts_bld_uint64(hpp, szp,
time_sup.r.o.os_monotonic_time_resolution);

k[i] = erts_bld_atom(hpp, szp, "used_resolution");
v[i++] = erts_bld_uint64(hpp, szp,
time_sup.r.o.os_monotonic_time_used_resolution);

k[i] = erts_bld_atom(hpp, szp, "extended");
v[i++] = time_sup.r.o.os_monotonic_time_extended ? am_yes : am_no;

Expand Down
1 change: 1 addition & 0 deletions erts/emulator/beam/sys.h
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,7 @@ typedef struct {
ErtsMonotonicTime sys_clock_resolution;
struct {
Uint64 resolution;
Uint64 used_resolution;
char *func;
char *clock_id;
int locked_use;
Expand Down
27 changes: 14 additions & 13 deletions erts/emulator/sys/win32/sys_time.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@
#include "erl_os_monotonic_time_extender.h"
#include "erl_time.h"

/* Need to look more closely at qpc before use... */
#define ERTS_DISABLE_USE_OF_QPC_FOR_MONOTONIC_TIME 1
/*
* How much to reduce the resolution of the by QueryPerformanceCounter()
* returned values in order to make them monotonic...
*/
#define ERTS_WIN_QPC_SKIP_BITS 10
#define ERTS_WIN_QPC_SKIP_MASK ((1 << ERTS_WIN_QPC_SKIP_BITS) - 1)

#define LL_LITERAL(X) ERTS_I64_LITERAL(X)

Expand Down Expand Up @@ -86,7 +90,7 @@ 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;
Uint32 pcf;
int using_get_tick_count_time_unit;
};

Expand Down Expand Up @@ -159,9 +163,9 @@ os_monotonic_time_qpc(void)
if (!(*internal_state.r.o.pQueryPerformanceCounter)(&pc))
erts_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n");
temp = (ErtsMonotonicTime) pc.QuadPart;
} while(!(temp & SKIP));
} while(!(temp & ERTS_WIN_QPC_SKIP_MASK));

return temp & (ERTS_I64_LITERAL(0xFFFFFFFFFFFFFFFF)-SKIP);
return temp & (ERTS_I64_LITERAL(0xFFFFFFFFFFFFFFFF)-ERTS_WIN_QPC_SKIP_MASK);
}

static void
Expand All @@ -170,16 +174,10 @@ os_times_qpc(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep)
LARGE_INTEGER pc;
SYSTEMTIME st;
ErtsSystemTime stime;
BOOL qpcr;

qpcr = (*internal_state.r.o.pQueryPerformanceCounter)(&pc);
*mtimep = os_monotonic_time_qpc();
GetSystemTime(&st);

if (!qpcr)
erts_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n");

*mtimep = (ErtsMonotonicTime) pc.QuadPart;

stime = SystemTime2MilliSec(&st);

*stimep = ((ErtsSystemTime)
Expand Down Expand Up @@ -372,7 +370,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp)
if (!internal_state.r.o.pQueryPerformanceCounter)
goto get_tick_count64;

if (pf.QuadPart > (((LONGLONG) 1) << 32))
if (pf.QuadPart >= (((LONGLONG) 1) << 32))
goto get_tick_count64;

internal_state.r.o.pcf = (Uint32) pf.QuadPart;
Expand All @@ -387,6 +385,9 @@ sys_init_time(ErtsSysInitTimeResult *init_resp)
time_unit = (ErtsMonotonicTime) pf.QuadPart;
internal_state.r.o.using_get_tick_count_time_unit = 0;
init_resp->os_monotonic_time_info.resolution = time_unit;
/* We reduce the used resolution in order to make it monotonic... */
init_resp->os_monotonic_time_info.used_resolution
= time_unit >> ERTS_WIN_QPC_SKIP_BITS;
os_mtime_func = os_monotonic_time_qpc;
os_times_func = os_times_qpc;
}
Expand Down