[winpr,sysinfo] unify time function use

* Add new function winpr_GetTickCount64NS for high resolution tick
  count with (up to) nanosecond resolution
* Add new function winpr_GetUnixTimeNS for high resolution system time
  as nanoseconds since 1.1.1970
* Replace use of clock_gettime and gettimeofday in whole project with
  these new functions
* Add new macros WINPR_TIME_NS_TO_* and WINPR_TIME_NS_REM_* to convert
  the nano second count to less resolution or get the remainder in the
  desired resolution
This commit is contained in:
akallabeth 2024-03-08 09:34:04 +01:00 committed by Martin Fleisz
parent b5713c46a7
commit 4732f379d4
10 changed files with 188 additions and 234 deletions

View File

@ -29,6 +29,7 @@
#include <time.h>
#include <winpr/string.h>
#include <winpr/sysinfo.h>
#ifndef _WIN32
#include <sys/param.h>
@ -69,28 +70,24 @@
#define PROFILER_STOP
#endif // GOOGLE_PROFILER
extern float _delta_time(const struct timespec* t0, const struct timespec* t1);
extern void _floatprint(float t, char* output);
extern float measure_delta_time(UINT64 t0, UINT64 t1);
extern void measure_floatprint(float t, char* output);
#ifndef CLOCK_MONOTONIC_RAW
#define CLOCK_MONOTONIC_RAW 4
#endif // !CLOCK_MONOTONIC_RAW
#define MEASURE_LOOP_START(_prefix_, _count_) \
{ \
struct timespec _start, _stop; \
char* _prefix; \
int _count = (_count_); \
int _loop; \
float _delta; \
char _str1[32], _str2[32]; \
_prefix = _strdup(_prefix_); \
_str1[0] = '\0'; \
_str2[0] = '\0'; \
clock_gettime(CLOCK_MONOTONIC_RAW, &_start); \
PROFILER_START(_prefix); \
_loop = (_count); \
do \
#define MEASURE_LOOP_START(_prefix_, _count_) \
{ \
UINT64 _start, _stop; \
char* _prefix; \
int _count = (_count_); \
int _loop; \
float _delta; \
char _str1[32], _str2[32]; \
_prefix = _strdup(_prefix_); \
_str1[0] = '\0'; \
_str2[0] = '\0'; \
_start = winpr_GetTickCount64NS(); \
PROFILER_START(_prefix); \
_loop = (_count); \
do \
{
#define MEASURE_LOOP_STOP \
@ -100,28 +97,28 @@ extern void _floatprint(float t, char* output);
#define MEASURE_GET_RESULTS(_result_) \
PROFILER_STOP; \
clock_gettime(CLOCK_MONOTONIC_RAW, &_stop); \
_delta = _delta_time(&_start, &_stop); \
_stop = winpr_GetTickCount64NS(); \
_delta = measure_delta_time(_start, _stop); \
(_result_) = (float)_count / _delta; \
free(_prefix); \
}
#define MEASURE_SHOW_RESULTS(_result_) \
PROFILER_STOP; \
clock_gettime(CLOCK_MONOTONIC_RAW, &_stop); \
_delta = _delta_time(&_start, &_stop); \
_stop = winpr_GetTickCount64NS(); \
_delta = measure_delta_time(_start, _stop); \
(_result_) = (float)_count / _delta; \
_floatprint((float)_count / _delta, _str1); \
measure_floatprint((float)_count / _delta, _str1); \
printf("%s: %9d iterations in %5.1f seconds = %s/s \n", _prefix, _count, _delta, _str1); \
free(_prefix); \
}
#define MEASURE_SHOW_RESULTS_SCALED(_scale_, _label_) \
PROFILER_STOP; \
clock_gettime(CLOCK_MONOTONIC_RAW, &_stop); \
_delta = _delta_time(&_start, &_stop); \
_floatprint((float)_count / _delta, _str1); \
_floatprint((float)_count / _delta * (_scale_), _str2); \
_stop = winpr_GetTickCount64NS(); \
_delta = measure_delta_time(_start, _stop); \
measure_floatprint((float)_count / _delta, _str1); \
measure_floatprint((float)_count / _delta * (_scale_), _str2); \
printf("%s: %9d iterations in %5.1f seconds = %s/s = %s%s \n", _prefix, _count, _delta, _str1, \
_str2, _label_); \
free(_prefix); \

View File

@ -36,31 +36,15 @@ int test_sizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
/* ------------------------------------------------------------------------- */
#ifdef _WIN32
float _delta_time(const struct timespec* t0, const struct timespec* t1)
float measure_delta_time(UINT64 t0, UINT64 t1)
{
return 0.0f;
INT64 diff = (INT64)(t1 - t0);
double retval = diff / 1000000000.0;
return (retval < 0.0) ? 0.0f : (float)retval;
}
#else
float _delta_time(const struct timespec* t0, const struct timespec* t1)
{
INT64 secs = (INT64)(t1->tv_sec) - (INT64)(t0->tv_sec);
long nsecs = t1->tv_nsec - t0->tv_nsec;
double retval = NAN;
if (nsecs < 0)
{
--secs;
nsecs += 1000000000;
}
retval = (double)secs + (double)nsecs / (double)1000000000.0;
return (retval < 0.0) ? 0.0 : (float)retval;
}
#endif
/* ------------------------------------------------------------------------- */
void _floatprint(float t, char* output)
void measure_floatprint(float t, char* output)
{
/* I don't want to link against -lm, so avoid log,exp,... */
float f = 10.0;

View File

@ -27,27 +27,11 @@
#include <winpr/assert.h>
#include <winpr/file.h>
#include <winpr/crt.h>
#include <winpr/sysinfo.h>
#include <freerdp/log.h>
#define TAG FREERDP_TAG("utils")
#ifndef _WIN32
#include <sys/time.h>
#else
#include <time.h>
#include <sys/timeb.h>
#include <winpr/windows.h>
int gettimeofday(struct timeval* tp, void* tz)
{
struct _timeb timebuffer;
_ftime(&timebuffer);
tp->tv_sec = (long)timebuffer.time;
tp->tv_usec = timebuffer.millitm * 1000;
return 0;
}
#endif
#include <freerdp/types.h>
#include <freerdp/utils/pcap.h>
@ -131,14 +115,11 @@ static BOOL pcap_write_record(rdpPcap* pcap, const pcap_record* record)
BOOL pcap_add_record(rdpPcap* pcap, const void* data, size_t length)
{
pcap_record* record = NULL;
struct timeval tp;
WINPR_ASSERT(pcap);
WINPR_ASSERT(data || (length == 0));
WINPR_ASSERT(length <= UINT32_MAX);
record = (pcap_record*)calloc(1, sizeof(pcap_record));
pcap_record* record = (pcap_record*)calloc(1, sizeof(pcap_record));
if (!record)
return FALSE;
@ -147,9 +128,10 @@ BOOL pcap_add_record(rdpPcap* pcap, const void* data, size_t length)
record->header.incl_len = (UINT32)length;
record->header.orig_len = (UINT32)length;
gettimeofday(&tp, 0);
record->header.ts_sec = (UINT32)tp.tv_sec;
record->header.ts_usec = (UINT32)tp.tv_usec;
const UINT64 ns = winpr_GetUnixTimeNS();
record->header.ts_sec = WINPR_TIME_NS_TO_S(ns);
record->header.ts_usec = WINPR_TIME_NS_REM_US(ns);
if (pcap->tail == NULL)
{

View File

@ -22,38 +22,18 @@
#include <stdio.h>
#include <stdlib.h>
#include <winpr/sysinfo.h>
#include <freerdp/utils/stopwatch.h>
#ifdef _WIN32
LARGE_INTEGER stopwatch_freq = { 0 };
#else
#include <sys/time.h>
#endif
static void stopwatch_set_time(UINT64* usecs)
{
#ifdef _WIN32
LARGE_INTEGER perfcount;
QueryPerformanceCounter(&perfcount);
*usecs = (perfcount.QuadPart * 1000000) / stopwatch_freq.QuadPart;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
*usecs = tv.tv_sec * 1000000 + tv.tv_usec;
#endif
const UINT64 ns = winpr_GetTickCount64NS();
*usecs = WINPR_TIME_NS_TO_US(ns);
}
STOPWATCH* stopwatch_create(void)
{
STOPWATCH* sw = NULL;
#ifdef _WIN32
if (stopwatch_freq.QuadPart == 0)
{
QueryPerformanceFrequency(&stopwatch_freq);
}
#endif
sw = (STOPWATCH*)malloc(sizeof(STOPWATCH));
STOPWATCH* sw = (STOPWATCH*)calloc(1, sizeof(STOPWATCH));
if (!sw)
return NULL;
stopwatch_reset(sw);

View File

@ -322,6 +322,17 @@ extern "C"
#endif
#define WINPR_TIME_NS_TO_S(ns) ((ns) / 1000000000ull)
#define WINPR_TIME_NS_TO_MS(ns) ((ns) / 1000000ull)
#define WINPR_TIME_NS_TO_US(ns) ((ns) / 1000ull)
#define WINPR_TIME_NS_REM_NS(ns) ((ns) % 1000000000ull)
#define WINPR_TIME_NS_REM_US(ns) (WINPR_TIME_NS_REM_NS(ns) / 1000ull)
#define WINPR_TIME_NS_REM_MS(ns) (WINPR_TIME_NS_REM_US(ns) / 1000ull)
WINPR_API UINT64 winpr_GetTickCount64NS(void);
WINPR_API UINT64 winpr_GetUnixTimeNS(void);
WINPR_API DWORD GetTickCountPrecise(void);
WINPR_API BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature);

View File

@ -248,15 +248,12 @@ BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response)
void ntlm_current_time(BYTE* timestamp)
{
FILETIME filetime = { 0 };
ULARGE_INTEGER time64 = { 0 };
FILETIME ft = { 0 };
WINPR_ASSERT(timestamp);
GetSystemTimeAsFileTime(&filetime);
time64.u.LowPart = filetime.dwLowDateTime;
time64.u.HighPart = filetime.dwHighDateTime;
CopyMemory(timestamp, &(time64.QuadPart), 8);
GetSystemTimeAsFileTime(&ft);
CopyMemory(timestamp, &(ft), sizeof(ft));
}
/**

View File

@ -707,11 +707,11 @@ static void timespec_add_ms(struct timespec* tspec, UINT32 ms)
static void timespec_gettimeofday(struct timespec* tspec)
{
struct timeval tval;
WINPR_ASSERT(tspec);
gettimeofday(&tval, NULL);
tspec->tv_sec = tval.tv_sec;
tspec->tv_nsec = tval.tv_usec * 1000;
const UINT64 ns = winpr_GetUnixTimeNS();
tspec->tv_sec = WINPR_TIME_NS_TO_S(ns);
tspec->tv_nsec = WINPR_TIME_NS_REM_NS(ns);
}
static INT64 timespec_compare(const struct timespec* tspec1, const struct timespec* tspec2)

View File

@ -59,60 +59,16 @@
#include "../pipe/pipe.h"
/* clock_gettime is not implemented on OSX prior to 10.12 */
#if defined(__MACH__) && defined(__APPLE__)
#include <mach/mach_time.h>
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 0
#endif
/* clock_gettime is not implemented on OSX prior to 10.12 */
int _mach_clock_gettime(int clk_id, struct timespec* t);
int _mach_clock_gettime(int clk_id, struct timespec* t)
static struct timespec ts_from_ns(void)
{
UINT64 time = 0;
double seconds = 0.0;
double nseconds = 0.0;
mach_timebase_info_data_t timebase = { 0 };
mach_timebase_info(&timebase);
time = mach_absolute_time();
nseconds = ((double)time * (double)timebase.numer) / ((double)timebase.denom);
seconds = ((double)time * (double)timebase.numer) / ((double)timebase.denom * 1e9);
t->tv_sec = seconds;
t->tv_nsec = nseconds;
return 0;
const UINT64 ns = winpr_GetUnixTimeNS();
struct timespec timeout = { 0 };
timeout.tv_sec = WINPR_TIME_NS_TO_S(ns);
timeout.tv_nsec = WINPR_TIME_NS_REM_NS(ns);
;
return timeout;
}
/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */
#ifdef __CLOCK_AVAILABILITY
/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be declared
* * but it may be NULL at runtime. So we need to check before using it. */
int _mach_safe_clock_gettime(int clk_id, struct timespec* t);
int _mach_safe_clock_gettime(int clk_id, struct timespec* t)
{
if (clock_gettime)
{
return clock_gettime(clk_id, t);
}
return _mach_clock_gettime(clk_id, t);
}
#define clock_gettime _mach_safe_clock_gettime
#else
#define clock_gettime _mach_clock_gettime
#endif
#endif
/**
* Drop in replacement for pthread_mutex_timedlock
* http://code.google.com/p/android/issues/detail?id=7807
@ -148,14 +104,14 @@ STATIC_NEEDED int pthread_mutex_timedlock(pthread_mutex_t* mutex,
unsigned long long diff = 0;
int retcode = -1;
/* This is just to avoid a completely busy wait */
clock_gettime(CLOCK_MONOTONIC, &timenow);
timenow = ts_from_ns();
diff = ts_difftime(&timenow, timeout);
sleepytime.tv_sec = diff / 1000000000LL;
sleepytime.tv_nsec = diff % 1000000000LL;
while ((retcode = pthread_mutex_trylock(mutex)) == EBUSY)
{
clock_gettime(CLOCK_MONOTONIC, &timenow);
timenow = ts_from_ns();
if (ts_difftime(timeout, &timenow) >= 0)
{
@ -237,8 +193,8 @@ DWORD WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertabl
if (dwMilliseconds != INFINITE)
{
int status = 0;
struct timespec timeout = { 0 };
clock_gettime(CLOCK_MONOTONIC, &timeout);
struct timespec timeout = ts_from_ns();
ts_add_ms(&timeout, dwMilliseconds);
status = pthread_mutex_timedlock(&mutex->mutex, &timeout);

View File

@ -33,9 +33,43 @@
#include <fcntl.h>
#endif
#if !defined(_WIN32)
#if defined(_POSIX_SOURCE) && (_POSIX_C_SOURCE >= 200112L)
#include <time.h>
#elif !defined(__APPLE__)
#include <sys/time.h>
#include <sys/sysinfo.h>
#endif
#endif
#include "../log.h"
#define TAG WINPR_TAG("sysinfo")
#define FILETIME_TO_UNIX_OFFSET_S 11644473600UL
#if defined(__MACH__) && defined(__APPLE__)
#include <mach/mach_time.h>
static UINT64 scaleHighPrecision(UINT64 i, UINT32 numer, UINT32 denom)
{
UINT64 high = (i >> 32) * numer;
UINT64 low = (i & 0xffffffffull) * numer / denom;
UINT64 highRem = ((high % denom) << 32) / denom;
high /= denom;
return (high << 32) + highRem + low;
}
static UINT64 mac_get_time_ns(void)
{
mach_timebase_info_data_t timebase = { 0 };
mach_timebase_info(&timebase);
UINT64 t = mach_absolute_time();
return scaleHighPrecision(t, timebase.numer, timebase.denom);
}
#endif
/**
* api-ms-win-core-sysinfo-l1-1-1.dll:
*
@ -272,13 +306,14 @@ BOOL SetLocalTime(CONST SYSTEMTIME* lpSystemTime)
VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
{
ULARGE_INTEGER time64;
time64.u.HighPart = 0;
/* time represented in tenths of microseconds since midnight of January 1, 1601 */
time64.QuadPart = time(NULL) + 11644473600LL; /* Seconds since January 1, 1601 */
time64.QuadPart *= 10000000; /* Convert timestamp to tenths of a microsecond */
lpSystemTimeAsFileTime->dwLowDateTime = time64.u.LowPart;
lpSystemTimeAsFileTime->dwHighDateTime = time64.u.HighPart;
union
{
UINT64 u64;
FILETIME ft;
} t;
t.u64 = (winpr_GetUnixTimeNS() / 100ull) + FILETIME_TO_UNIX_OFFSET_S * 10000000ull;
*lpSystemTimeAsFileTime = t.ft;
}
BOOL GetSystemTimeAdjustment(PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement,
@ -294,25 +329,7 @@ BOOL GetSystemTimeAdjustment(PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement,
DWORD GetTickCount(void)
{
DWORD ticks = 0;
#ifdef __linux__
struct timespec ts;
if (!clock_gettime(CLOCK_MONOTONIC_RAW, &ts))
ticks = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
#else
/**
* FIXME: this is relative to the Epoch time, and we
* need to return a value relative to the system uptime.
*/
struct timeval tv;
if (!gettimeofday(&tv, NULL))
ticks = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
#endif
return ticks;
return GetTickCount64();
}
#endif // _WIN32
@ -553,35 +570,80 @@ DWORD GetTickCount(void)
ULONGLONG winpr_GetTickCount64(void)
{
ULONGLONG ticks = 0;
#if defined(__linux__)
struct timespec ts;
const UINT64 ns = winpr_GetTickCount64NS();
return WINPR_TIME_NS_TO_MS(ns);
}
if (!clock_gettime(CLOCK_MONOTONIC_RAW, &ts))
ticks = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
#endif
UINT64 winpr_GetTickCount64NS(void)
{
UINT64 ticks = 0;
#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)
struct timespec ts = { 0 };
if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) == 0)
ticks = (ts.tv_sec * 1000000000ull) + ts.tv_nsec;
#elif defined(__MACH__) && defined(__APPLE__)
ticks = mac_get_time_ns();
#elif defined(_WIN32)
FILETIME ft;
ULARGE_INTEGER ul;
GetSystemTimeAsFileTime(&ft);
ul.LowPart = ft.dwLowDateTime;
ul.HighPart = ft.dwHighDateTime;
ticks = ul.QuadPart;
LARGE_INTEGER li = { 0 };
LARGE_INTEGER freq = { 0 };
if (QueryPerformanceFrequency(&freq) && QueryPerformanceCounter(&li))
ticks = li.QuadPart * 1000000000ull / freq.QuadPart;
#else
/**
* FIXME: this is relative to the Epoch time, and we
* need to return a value relative to the system uptime.
struct timeval tv = { 0 };
if (gettimeofday(&tv, NULL) == 0)
ticks = (tv.tv_sec * 1000000000ull) + (tv.tv_usec * 1000ull);
/* We need to trick here:
* this function should return the system uptime, but we need higher resolution.
* so on first call get the actual timestamp along with the system uptime.
*
* return the uptime measured from now on (e.g. current measure - first measure + uptime at
* first measure)
*/
struct timeval tv;
if (!gettimeofday(&tv, NULL))
ticks = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
static UINT64 first = 0;
static UINT64 uptime = 0;
if (first == 0)
{
struct sysinfo info = { 0 };
if (sysinfo(&info) == 0)
{
first = ticks;
uptime = 1000000000ull * info.uptime;
}
}
ticks = ticks - first + uptime;
#endif
return ticks;
}
UINT64 winpr_GetUnixTimeNS(void)
{
#if defined(_WIN32)
union
{
UINT64 u64;
FILETIME ft;
} t = { 0 };
GetSystemTimeAsFileTime(&t.ft);
return (t.u64 - FILETIME_TO_UNIX_OFFSET_S * 10000000ull) * 100ull;
#elif _POSIX_C_SOURCE >= 200112L
struct timespec ts = { 0 };
if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
return 0;
return ts.tv_sec * 1000000000ull + ts.tv_nsec;
#else
struct timeval tv = { 0 };
if (gettimeofday(&tv, NULL) != 0)
return 0;
return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000ull;
#endif
}
/* If x86 */
#ifdef _M_IX86_AMD64

View File

@ -29,27 +29,11 @@
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/stream.h>
#include <winpr/sysinfo.h>
#include "../../log.h"
#define TAG WINPR_TAG("utils.wlog")
#ifndef _WIN32
#include <sys/time.h>
#else
#include <time.h>
#include <sys/timeb.h>
#include <winpr/windows.h>
static int gettimeofday(struct timeval* tp, void* tz)
{
struct _timeb timebuffer;
_ftime(&timebuffer);
tp->tv_sec = (long)timebuffer.time;
tp->tv_usec = timebuffer.millitm * 1000;
return 0;
}
#endif
static BOOL Pcap_Read_Header(wPcap* pcap, wPcapHeader* header)
{
if (pcap && pcap->fp && fread((void*)header, sizeof(wPcapHeader), 1, pcap->fp) == 1)
@ -89,8 +73,7 @@ static BOOL Pcap_Read_Record(wPcap* pcap, wPcapRecord* record)
static BOOL Pcap_Add_Record(wPcap* pcap, void* data, UINT32 length)
{
wPcapRecord* record;
struct timeval tp;
wPcapRecord* record = NULL;
if (!pcap->tail)
{
@ -117,9 +100,10 @@ static BOOL Pcap_Add_Record(wPcap* pcap, void* data, UINT32 length)
record->length = length;
record->header.incl_len = length;
record->header.orig_len = length;
gettimeofday(&tp, 0);
record->header.ts_sec = tp.tv_sec;
record->header.ts_usec = tp.tv_usec;
UINT64 ns = winpr_GetUnixTimeNS();
record->header.ts_sec = WINPR_TIME_NS_TO_S(ns);
record->header.ts_usec = WINPR_TIME_NS_REM_US(ns);
return TRUE;
}
@ -380,7 +364,6 @@ BOOL WLog_PacketMessage_Write(wPcap* pcap, void* data, size_t length, DWORD flag
{
wTcpHeader tcp;
wIPv4Header ipv4;
struct timeval tp;
wPcapRecord record;
wEthernetHeader ethernet;
ethernet.Type = 0x0800;
@ -474,9 +457,11 @@ BOOL WLog_PacketMessage_Write(wPcap* pcap, void* data, size_t length, DWORD flag
record.header.incl_len = (UINT32)record.length + offset;
record.header.orig_len = (UINT32)record.length + offset;
record.next = NULL;
gettimeofday(&tp, 0);
record.header.ts_sec = tp.tv_sec;
record.header.ts_usec = tp.tv_usec;
UINT64 ns = winpr_GetUnixTimeNS();
record.header.ts_sec = WINPR_TIME_NS_TO_S(ns);
record.header.ts_usec = WINPR_TIME_NS_REM_US(ns);
if (!Pcap_Write_RecordHeader(pcap, &record.header) ||
!WLog_PacketMessage_Write_EthernetHeader(pcap, &ethernet) ||
!WLog_PacketMessage_Write_IPv4Header(pcap, &ipv4) ||