Skip to content

Instantly share code, notes, and snippets.

@marakew
Created December 5, 2023 12:12
Show Gist options
  • Save marakew/af8a086d8ec9420ef9a64d12ec7e0353 to your computer and use it in GitHub Desktop.
Save marakew/af8a086d8ec9420ef9a64d12ec7e0353 to your computer and use it in GitHub Desktop.
#if defined(_WIN32)
//jrtplib
inline unsigned __int64 CalculateFileTime(unsigned __int64 performancecount, unsigned __int64 performancefrequency)
{
unsigned __int64 f = performancefrequency;
unsigned __int64 a = performancecount;
unsigned __int64 b = a/f;
unsigned __int64 c = a%f; // a = b*f+c => (a*10'000'000)/f = b*10'000'000+(c*10'000'000)/f
return b*10'000'000ui64+(c*10'000'000ui64)/f;
}
//https://github.com/Perl/perl5/blob/blead/dist/Time-HiRes/HiRes.xs
union FT_t
{
unsigned __int64 ft_i64;
FILETIME ft_val;
};
struct my_ctx
{
unsigned long run_count;
unsigned __int64 base_ticks;
unsigned __int64 tick_frequency;
FT_t base_systime_as_filetime;
unsigned __int64 reset_time;
};
/* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
#define EPOCH_BIAS (116444736000000000LL)
/* If the performance counter delta drifts more than 0.5 seconds from the
* system time then we recalibrate to the system time. This means we may
* move *backwards* in time! */
#define MAX_PERF_COUNTER_SKEW (5000000LL) /* 0.5 seconds */
/* Reset reading from the performance counter every five minutes.
* Many PC clocks just seem to be so bad. */
#define MAX_PERF_COUNTER_TICKS (300000000LL) /* 300 seconds */
/*
* Windows 8 introduced GetSystemTimePreciseAsFileTime(), but currently we have
* to support older systems, so for now we provide our own implementation.
* In the future we will switch to the real deal.
*/
static void _GetSystemTimePreciseAsFileTime(FILETIME *out)
{
static my_ctx MY_CTX;
FT_t ft;
if (MY_CTX.run_count++ == 0 ||
MY_CXT.base_systime_as_filetime.ft_i64 > MY_CXT.reset_time)
{
::QueryPerformanceFrequency((LARGE_INTEGER*)&MY_CTX.tick_frequency);
::QueryPerformanceCounter((LARGE_INTEGER*)&MY_CTX.base_ticks);
::GetSystemTimeAsFileTime(&MY_CTX.base_systime_as_filetime.ft_val);
ft.ft_i64 = MY_CTX.base_systime_as_filetime.ft_i64;
MY_CXT.reset_time = ft.ft_i64 + MAX_PERF_COUNTER_TICKS;
} else
{
__int64 diff;
unsigned __int64 ticks;
::QueryPerformanceCounter((LARGE_INTEGER*)&ticks);
ticks -= MY_CTX.base_ticks;
//ft.ft_i64 = MY_CTX.base_systime_as_filetime.ft_i64 + CalculateFileTime(ticks, MY_CTX.tick_frequency);
ft.ft_i64 = MY_CTX.base_systime_as_filetime.ft_i64
+ (ticks / MY_CTX.tick_frequency) * 10'000'000LL
+ ((ticks % MY_CTX.tick_frequency) * 10'000'000LL) / MY_CTX.tick_frequency;
diff = ft.ft_i64 - MY_CXT.base_systime_as_filetime.ft_i64;
if (diff < -MAX_PERF_COUNTER_SKEW || diff > MAX_PERF_COUNTER_SKEW)
{
MY_CXT.base_ticks += ticks;
::GetSystemTimeAsFileTime(&MY_CXT.base_systime_as_filetime.ft_val);
ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64;
}
}
*out = ft.ft_val;
}
static int gettimeofday(struct timeval *tv, void *tz)
{
FT_t ft;
_GetSystemTimePreciseAsFileTime(&ft.ft_val);
/* seconds since epoch */
tv->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / 10LL / 1'000'000LL);
/* microseconds remaining */
tv->tv_usec = (long)((ft.ft_i64 / 10LL) % 1'000'000LL);
return 0;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment