mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-04-21 14:24:43 +00:00
Improve time/sleep accuracy on Windows
It's now almost as good as Linux thanks to a Windows 8+ API.
This commit is contained in:
parent
72ac5f18d9
commit
8caf1b48a9
9 changed files with 76 additions and 31 deletions
|
@ -40,7 +40,11 @@ static dontinline int __clk_tck_init(void) {
|
||||||
size_t len;
|
size_t len;
|
||||||
struct clockinfo_netbsd clock;
|
struct clockinfo_netbsd clock;
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
x = 1000;
|
// MSVC defines CLK_TCK as 1000 but 1ms is obviously not the
|
||||||
|
// scheduling quantum Windows actually uses. If we define it
|
||||||
|
// as 30 rather than 1000, then clock_nanosleep is much more
|
||||||
|
// accurately able to predict the duration of its busy waits
|
||||||
|
x = 30;
|
||||||
} else if (IsXnu() || IsOpenbsd()) {
|
} else if (IsXnu() || IsOpenbsd()) {
|
||||||
x = 100;
|
x = 100;
|
||||||
} else if (IsFreebsd()) {
|
} else if (IsFreebsd()) {
|
||||||
|
|
|
@ -25,14 +25,20 @@
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/time/time.h"
|
#include "libc/time/time.h"
|
||||||
|
|
||||||
static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real) {
|
static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real,
|
||||||
if (clock == CLOCK_REALTIME) {
|
int64_t real_coarse, int64_t boot) {
|
||||||
ts->tv_sec = 0;
|
ts->tv_sec = 0;
|
||||||
|
if (clock == CLOCK_REALTIME) {
|
||||||
ts->tv_nsec = real;
|
ts->tv_nsec = real;
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (clock == CLOCK_REALTIME_COARSE) {
|
||||||
|
ts->tv_nsec = real_coarse;
|
||||||
|
return 0;
|
||||||
} else if (clock == CLOCK_MONOTONIC) {
|
} else if (clock == CLOCK_MONOTONIC) {
|
||||||
ts->tv_sec = 0;
|
ts->tv_nsec = 10;
|
||||||
ts->tv_nsec = 1;
|
return 0;
|
||||||
|
} else if (clock == CLOCK_BOOTTIME) {
|
||||||
|
ts->tv_nsec = boot;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return einval();
|
return einval();
|
||||||
|
@ -40,11 +46,11 @@ static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sys_clock_getres_nt(int clock, struct timespec *ts) {
|
static int sys_clock_getres_nt(int clock, struct timespec *ts) {
|
||||||
return sys_clock_getres_poly(clock, ts, 100);
|
return sys_clock_getres_poly(clock, ts, 100, 1000000, 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sys_clock_getres_xnu(int clock, struct timespec *ts) {
|
static int sys_clock_getres_xnu(int clock, struct timespec *ts) {
|
||||||
return sys_clock_getres_poly(clock, ts, 1000);
|
return sys_clock_getres_poly(clock, ts, 1000, 1000, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,26 +18,61 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/calls/struct/timespec.internal.h"
|
#include "libc/calls/struct/timespec.internal.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/wintime.internal.h"
|
#include "libc/fmt/wintime.internal.h"
|
||||||
#include "libc/nt/struct/filetime.h"
|
|
||||||
#include "libc/nt/synchronization.h"
|
#include "libc/nt/synchronization.h"
|
||||||
#include "libc/sysv/consts/clock.h"
|
|
||||||
|
#define _CLOCK_REALTIME 0
|
||||||
|
#define _CLOCK_MONOTONIC 1
|
||||||
|
#define _CLOCK_REALTIME_COARSE 2
|
||||||
|
#define _CLOCK_BOOTTIME 3
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
uint64_t base;
|
||||||
|
uint64_t freq;
|
||||||
|
} g_winclock;
|
||||||
|
|
||||||
textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
|
textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
|
||||||
|
uint64_t t;
|
||||||
struct NtFileTime ft;
|
struct NtFileTime ft;
|
||||||
if (clock == CLOCK_REALTIME) {
|
switch (clock) {
|
||||||
if (!ts) return 0;
|
case _CLOCK_REALTIME:
|
||||||
|
if (ts) {
|
||||||
|
GetSystemTimePreciseAsFileTime(&ft);
|
||||||
|
*ts = FileTimeToTimeSpec(ft);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case _CLOCK_REALTIME_COARSE:
|
||||||
|
if (ts) {
|
||||||
GetSystemTimeAsFileTime(&ft);
|
GetSystemTimeAsFileTime(&ft);
|
||||||
*ts = FileTimeToTimeSpec(ft);
|
*ts = FileTimeToTimeSpec(ft);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else if (clock == CLOCK_MONOTONIC) {
|
case _CLOCK_MONOTONIC:
|
||||||
if (!ts) return 0;
|
if (ts) {
|
||||||
return sys_clock_gettime_mono(ts);
|
QueryPerformanceCounter(&t);
|
||||||
} else if (clock == CLOCK_BOOTTIME) {
|
t = ((t - g_winclock.base) * 1000000000) / g_winclock.freq;
|
||||||
if (ts) *ts = timespec_frommillis(GetTickCount64());
|
*ts = timespec_fromnanos(t);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
case _CLOCK_BOOTTIME:
|
||||||
|
if (ts) {
|
||||||
|
*ts = timespec_frommillis(GetTickCount64());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static textstartup void winclock_init() {
|
||||||
|
if (IsWindows()) {
|
||||||
|
QueryPerformanceCounter(&g_winclock.base);
|
||||||
|
QueryPerformanceFrequency(&g_winclock.freq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *const winclock_ctor[] initarray = {
|
||||||
|
winclock_init,
|
||||||
|
};
|
||||||
|
|
|
@ -65,7 +65,7 @@ static textwindows int sys_utimensat_nt_impl(int dirfd, const char *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ts || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
|
if (!ts || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
|
||||||
GetSystemTimeAsFileTime(ft);
|
GetSystemTimePreciseAsFileTime(ft);
|
||||||
}
|
}
|
||||||
if (ts) {
|
if (ts) {
|
||||||
for (i = 0; i < 2; ++i) {
|
for (i = 0; i < 2; ++i) {
|
||||||
|
|
|
@ -59,7 +59,7 @@ uint32_t SleepEx(uint32_t dwMilliseconds, bool32 bAlertable);
|
||||||
void GetSystemTime(struct NtSystemTime *lpSystemTime);
|
void GetSystemTime(struct NtSystemTime *lpSystemTime);
|
||||||
bool32 SystemTimeToFileTime(const struct NtSystemTime *lpSystemTime,
|
bool32 SystemTimeToFileTime(const struct NtSystemTime *lpSystemTime,
|
||||||
struct NtFileTime *lpFileTime);
|
struct NtFileTime *lpFileTime);
|
||||||
void GetSystemTimeAsFileTime(struct NtFileTime *); /* win8+ */
|
void GetSystemTimeAsFileTime(struct NtFileTime *);
|
||||||
void GetSystemTimePreciseAsFileTime(struct NtFileTime *); /* win8+ */
|
void GetSystemTimePreciseAsFileTime(struct NtFileTime *); /* win8+ */
|
||||||
|
|
||||||
uint32_t WaitForSingleObject(int64_t hHandle, uint32_t dwMilliseconds);
|
uint32_t WaitForSingleObject(int64_t hHandle, uint32_t dwMilliseconds);
|
||||||
|
@ -110,8 +110,8 @@ void TryAcquireSRWLockShared(intptr_t *);
|
||||||
|
|
||||||
uint64_t GetTickCount64(void);
|
uint64_t GetTickCount64(void);
|
||||||
|
|
||||||
bool32 QueryPerformanceFrequency(int64_t *lpFrequency);
|
bool32 QueryPerformanceFrequency(uint64_t *lpFrequency);
|
||||||
bool32 QueryPerformanceCounter(int64_t *lpPerformanceCount);
|
bool32 QueryPerformanceCounter(uint64_t *lpPerformanceCount);
|
||||||
bool32 GetSystemTimeAdjustment(uint32_t *lpTimeAdjustment,
|
bool32 GetSystemTimeAdjustment(uint32_t *lpTimeAdjustment,
|
||||||
uint32_t *lpTimeIncrement,
|
uint32_t *lpTimeIncrement,
|
||||||
bool32 *lpTimeAdjustmentDisabled);
|
bool32 *lpTimeAdjustmentDisabled);
|
||||||
|
|
|
@ -578,7 +578,7 @@ syscon close CLOSE_RANGE_CLOEXEC 4 4 -1 -1 -1 -1 -1 -1 #
|
||||||
syscon clock CLOCK_REALTIME 0 0 0 0 0 0 0 0 # consensus
|
syscon clock CLOCK_REALTIME 0 0 0 0 0 0 0 0 # consensus
|
||||||
syscon clock CLOCK_REALTIME_PRECISE 0 0 0 0 9 0 0 0 #
|
syscon clock CLOCK_REALTIME_PRECISE 0 0 0 0 9 0 0 0 #
|
||||||
syscon clock CLOCK_REALTIME_FAST 0 0 0 0 10 0 0 0 #
|
syscon clock CLOCK_REALTIME_FAST 0 0 0 0 10 0 0 0 #
|
||||||
syscon clock CLOCK_REALTIME_COARSE 5 5 0 0 10 0 0 0 # Linux 2.6.32+; bsd consensus; not available on RHEL5
|
syscon clock CLOCK_REALTIME_COARSE 5 5 0 0 10 0 0 2 # Linux 2.6.32+; bsd consensus; not available on RHEL5
|
||||||
syscon clock CLOCK_MONOTONIC 1 1 1 6 4 3 3 1 # XNU/NT faked; could move backwards if NTP introduces negative leap second
|
syscon clock CLOCK_MONOTONIC 1 1 1 6 4 3 3 1 # XNU/NT faked; could move backwards if NTP introduces negative leap second
|
||||||
syscon clock CLOCK_MONOTONIC_PRECISE 1 1 1 6 11 3 3 1 #
|
syscon clock CLOCK_MONOTONIC_PRECISE 1 1 1 6 11 3 3 1 #
|
||||||
syscon clock CLOCK_MONOTONIC_FAST 1 1 1 6 12 3 3 1 #
|
syscon clock CLOCK_MONOTONIC_FAST 1 1 1 6 12 3 3 1 #
|
||||||
|
@ -587,7 +587,7 @@ syscon clock CLOCK_MONOTONIC_RAW 4 4 127 4 127 127 127 127 # a
|
||||||
syscon clock CLOCK_PROCESS_CPUTIME_ID 2 2 127 12 15 2 0x40000000 127 # NetBSD lets you bitwise a PID into clockid_t
|
syscon clock CLOCK_PROCESS_CPUTIME_ID 2 2 127 12 15 2 0x40000000 127 # NetBSD lets you bitwise a PID into clockid_t
|
||||||
syscon clock CLOCK_THREAD_CPUTIME_ID 3 3 127 16 14 4 0x20000000 127 #
|
syscon clock CLOCK_THREAD_CPUTIME_ID 3 3 127 16 14 4 0x20000000 127 #
|
||||||
syscon clock CLOCK_PROF 127 127 127 127 2 127 2 127 #
|
syscon clock CLOCK_PROF 127 127 127 127 2 127 2 127 #
|
||||||
syscon clock CLOCK_BOOTTIME 7 7 7 127 127 6 127 7 #
|
syscon clock CLOCK_BOOTTIME 7 7 7 127 127 6 127 3 #
|
||||||
syscon clock CLOCK_REALTIME_ALARM 8 8 127 127 127 127 127 127 #
|
syscon clock CLOCK_REALTIME_ALARM 8 8 127 127 127 127 127 127 #
|
||||||
syscon clock CLOCK_BOOTTIME_ALARM 9 9 127 127 127 127 127 127 #
|
syscon clock CLOCK_BOOTTIME_ALARM 9 9 127 127 127 127 127 127 #
|
||||||
syscon clock CLOCK_TAI 11 11 127 127 127 127 127 127 #
|
syscon clock CLOCK_TAI 11 11 127 127 127 127 127 127 #
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon clock,CLOCK_BOOTTIME,7,7,7,127,127,6,127,7
|
.syscon clock,CLOCK_BOOTTIME,7,7,7,127,127,6,127,3
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon clock,CLOCK_REALTIME_COARSE,5,5,0,0,10,0,0,0
|
.syscon clock,CLOCK_REALTIME_COARSE,5,5,0,0,10,0,0,2
|
||||||
|
|
|
@ -50,7 +50,7 @@ TEST(clock_gettime, testClockRealtime) {
|
||||||
EXPECT_LT((unsigned)ABS(ts.tv_sec - tv.tv_sec), 5u);
|
EXPECT_LT((unsigned)ABS(ts.tv_sec - tv.tv_sec), 5u);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCH(clock_gettime, bench) {
|
TEST(clock_gettime, bench) {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
gettimeofday(&tv, 0); // trigger init
|
gettimeofday(&tv, 0); // trigger init
|
||||||
|
|
Loading…
Add table
Reference in a new issue