Skip to content

Commit 07507f2

Browse files
committed
[PC] precise gettimeofday() for Windows 7
1 parent b71d877 commit 07507f2

File tree

2 files changed

+65
-16
lines changed

2 files changed

+65
-16
lines changed

lib/compat/compat_gettimeofday.c

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,87 @@
22

33
#include <sys/time.h>
44

5-
// precise gettimeofday on Windows
65
#if defined(_WIN32)
6+
// precise gettimeofday on Windows
77

8-
9-
// a) use GetSystemTimePreciseAsFileTime
8+
// a) use GetSystemTimePreciseAsFileTime (not available on Windows 7)
109
#include <windows.h>
10+
#include <stdint.h>
11+
#include <stdio.h>
12+
13+
#define FILETIME2US(FT) ((((uint64_t)FT.dwHighDateTime) << 32 | ((uint64_t)FT.dwLowDateTime)) / 10 - (int64_t)11644473600000000)
14+
#define PERFCOUNT2US(PC, FREQ) (PC.QuadPart / 1000.0 / FREQ)
15+
1116
int compat_gettimeofday(struct timeval *tv, struct timezone* tz)
1217
{
13-
FILETIME ft;
14-
unsigned __int64 tmpres = 0;
18+
uint64_t tmpres = 0;
19+
FILETIME ft; // 100-nanosecond intervals since January 1, 1601
20+
21+
#ifndef USE_GETSYSTEMTIMEPRECISEASFILETIME
22+
// Workaround for missing GetSystemTimePreciseAsFileTime
23+
// This should work on Windows Xp and above
24+
static uint64_t tmref = 0; // reference time (microseconds)
25+
static int64_t pcref = -3600000000L; // reference counter (microseconds)
26+
static double frequency = -1.0; // performance frequency (GHz)
27+
28+
// Obtain performance frequency
29+
if (frequency == -1.0)
30+
{
31+
LARGE_INTEGER freq;
32+
if (!QueryPerformanceFrequency(&freq))
33+
{
34+
// Cannot use QueryPerformanceCounter
35+
frequency = 0.0;
36+
}
37+
else
38+
{
39+
frequency = (double) freq.QuadPart / 1000000000.0; // GHz
40+
}
41+
}
42+
#endif
1543

1644
if (tv != NULL)
1745
{
18-
#if !defined(_UCRT)
19-
GetSystemTimeAsFileTime(&ft); // low precision (16ms)
46+
#ifdef USE_GETSYSTEMTIMEPRECISEASFILETIME
47+
GetSystemTimePreciseAsFileTime(&ft); // high precision wall time (<1 ms)
48+
tmpres = FILETIME2US(ft);
2049
#else
21-
GetSystemTimePreciseAsFileTime(&ft); // high precision (1<ms)
50+
if (frequency == 0.0)
51+
{
52+
// Cannot use QueryPerformanceCounter, only low precision time is available
53+
GetSystemTimeAsFileTime(&ft); // low precision wall time
54+
tmpres = FILETIME2US(ft); // to us
55+
}
56+
else
57+
{
58+
// Combine low precision wall time with high precision counter
59+
int64_t pcpres;
60+
int64_t pcdelta;
61+
LARGE_INTEGER pc;
62+
QueryPerformanceCounter(&pc); // high precision counter
63+
pcpres = PERFCOUNT2US(pc, frequency); // to us
64+
pcdelta = pcpres - pcref;
65+
if (pcdelta >= 3600000000L) // sync low precision time at start and then once per hour
66+
{
67+
printf("time sync\n");
68+
// obtain new reference time
69+
GetSystemTimeAsFileTime(&ft); // low precision wall time
70+
tmref = FILETIME2US(ft); // to us
71+
pcref = pcpres;
72+
pcdelta = 0;
73+
}
74+
// Current time as low precision reference time + high precision counter delta
75+
tmpres = tmref + pcdelta;
76+
}
2277
#endif
23-
tmpres |= ft.dwHighDateTime;
24-
tmpres <<= 32;
25-
tmpres |= ft.dwLowDateTime;
26-
tmpres /= 10; // convert into microseconds
27-
tmpres -= (__int64) 11644473600000000;
2878
tv->tv_sec = (long) (tmpres / 1000000UL);
2979
tv->tv_usec = (long) (tmpres % 1000000UL);
3080
}
3181
(void) tz;
3282
return 0;
3383
}
3484

35-
36-
// // b) use C++ chrono (portable, slower) (rename file to .cpp)
85+
// // b) use C++ chrono (portable, slower, MSYS2/CLANG64: fatal error: 'chrono' file not found)
3786
// #include <chrono>
3887
// int compat_gettimeofday(struct timeval* tp, struct timezone* tzp)
3988
// {

lib/hardware/fnSystem.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ void SystemManager::delay_microseconds(uint32_t us)
367367
LARGE_INTEGER freq;
368368
if (!QueryPerformanceFrequency (&freq))
369369
{
370-
Debug_println("QueryPerformanceCounter failed");
370+
Debug_println("QueryPerformanceFrequency failed");
371371
// Cannot use QueryPerformanceCounter.
372372
Sleep (us / 1000);
373373
return;

0 commit comments

Comments
 (0)