Last active
March 3, 2018 23:49
-
-
Save notwa/b5f3aefcbc9dabe2befd5739d7b6f289 to your computer and use it in GitHub Desktop.
portable snippets clock.h without pulling in windows.h — https://github.com/nemequ/portable-snippets
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Clocks (v1) | |
* Portable Snippets - https://github.com/nemequ/portable-snippets | |
* Created by Evan Nemerson <[email protected]> | |
* | |
* To the extent possible under law, the authors have waived all | |
* copyright and related or neighboring rights to this code. For | |
* details, see the Creative Commons Zero 1.0 Universal license at | |
* https://creativecommons.org/publicdomain/zero/1.0/ | |
* | |
* Modified by Connor Olding, 2017 | |
*/ | |
#if !defined(PSNIP_CLOCK_H) | |
#define PSNIP_CLOCK_H | |
#if !defined(PSNIP_CLOCK_STATIC_INLINE) | |
# if defined(__GNUC__) | |
# define PSNIP_CLOCK__COMPILER_ATTRIBUTES __attribute__((__unused__)) | |
# else | |
# define PSNIP_CLOCK__COMPILER_ATTRIBUTES | |
# endif | |
# define PSNIP_CLOCK__FUNCTION PSNIP_CLOCK__COMPILER_ATTRIBUTES static | |
#endif | |
enum PsnipClockType { | |
/* This clock provides the current time, in units since 1970-01-01 | |
* 00:00:00 UTC not including leap seconds. In other words, UNIX | |
* time. Keep in mind that this clock doesn't account for leap | |
* seconds, and can go backwards (think NTP adjustments). */ | |
PSNIP_CLOCK_TYPE_WALL = 1, | |
/* The CPU time is a clock which increases only when the current | |
* process is active (i.e., it doesn't increment while blocking on | |
* I/O). */ | |
PSNIP_CLOCK_TYPE_CPU = 2, | |
/* Monotonic time is always running (unlike CPU time), but it only | |
ever moves forward unless you reboot the system. Things like NTP | |
adjustments have no effect on this clock. */ | |
PSNIP_CLOCK_TYPE_MONOTONIC = 3 | |
}; | |
struct PsnipClockTimespec { | |
uint64_t seconds; | |
uint64_t nanoseconds; | |
}; | |
/* Methods we support: */ | |
#define PSNIP_CLOCK_METHOD_CLOCK_GETTIME 1 | |
#define PSNIP_CLOCK_METHOD_TIME 2 | |
#define PSNIP_CLOCK_METHOD_GETTIMEOFDAY 3 | |
#define PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER 4 | |
#define PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME 5 | |
#define PSNIP_CLOCK_METHOD_CLOCK 6 | |
#define PSNIP_CLOCK_METHOD_GETPROCESSTIMES 7 | |
#define PSNIP_CLOCK_METHOD_GETRUSAGE 8 | |
#define PSNIP_CLOCK_METHOD_GETSYSTEMTIMEPRECISEASFILETIME 9 | |
#define PSNIP_CLOCK_METHOD_GETTICKCOUNT64 10 | |
#include <assert.h> | |
#if defined(HEDLEY_UNREACHABLE) | |
# define PSNIP_CLOCK_UNREACHABLE() HEDLEY_UNREACHABLE() | |
#else | |
# define PSNIP_CLOCK_UNREACHABLE() assert(0) | |
#endif | |
/* Choose an implementation */ | |
/* #undef PSNIP_CLOCK_WALL_METHOD */ | |
/* #undef PSNIP_CLOCK_CPU_METHOD */ | |
/* #undef PSNIP_CLOCK_MONOTONIC_METHOD */ | |
/* We want to be able to detect the libc implementation, so we include | |
<limits.h> (<features.h> isn't available everywhere). */ | |
#if defined(__unix__) || defined(__unix) || defined(__linux__) | |
# include <limits.h> | |
# include <unistd.h> | |
#endif | |
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) | |
/* These are known to work without librt. If you know of others | |
* please let us know so we can add them. */ | |
# if \ | |
(defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17))) || \ | |
(defined(__FreeBSD__)) | |
# define PSNIP_CLOCK_HAVE_CLOCK_GETTIME | |
# elif !defined(PSNIP_CLOCK_NO_LIBRT) | |
# define PSNIP_CLOCK_HAVE_CLOCK_GETTIME | |
# endif | |
#endif | |
#if defined(_WIN32) | |
# if !defined(PSNIP_CLOCK_CPU_METHOD) | |
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_GETPROCESSTIMES | |
# endif | |
# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) | |
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER | |
# endif | |
#endif | |
#if defined(__MACH__) | |
# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) | |
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME | |
# endif | |
#endif | |
#if defined(PSNIP_CLOCK_HAVE_CLOCK_GETTIME) | |
# include <time.h> | |
# if !defined(PSNIP_CLOCK_WALL_METHOD) | |
# if defined(CLOCK_REALTIME_PRECISE) | |
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
# define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME_PRECISE | |
# elif !defined(__sun) | |
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
# define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME | |
# endif | |
# endif | |
# if !defined(PSNIP_CLOCK_CPU_METHOD) | |
# if defined(_POSIX_CPUTIME) || defined(CLOCK_PROCESS_CPUTIME_ID) | |
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
# define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_PROCESS_CPUTIME_ID | |
# elif defined(CLOCK_VIRTUAL) | |
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
# define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_VIRTUAL | |
# endif | |
# endif | |
# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) | |
# if defined(CLOCK_MONOTONIC_RAW) && !defined(__EMSCRIPTEN__) | |
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
# define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC_RAW | |
# elif defined(CLOCK_MONOTONIC_PRECISE) | |
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
# define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC_PRECISE | |
# elif defined(_POSIX_MONOTONIC_CLOCK) || defined(CLOCK_MONOTONIC) | |
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
# define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC | |
# endif | |
# endif | |
#endif | |
#if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L) | |
# if !defined(PSNIP_CLOCK_WALL_METHOD) | |
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_GETTIMEOFDAY | |
# endif | |
#endif | |
#if !defined(PSNIP_CLOCK_WALL_METHOD) | |
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_TIME | |
#endif | |
#if !defined(PSNIP_CLOCK_CPU_METHOD) | |
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK | |
#endif | |
/* Primarily here for testing. */ | |
#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) && defined(PSNIP_CLOCK_REQUIRE_MONOTONIC) | |
# error No monotonic clock found. | |
#endif | |
/* Implementations */ | |
#if \ | |
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \ | |
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \ | |
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \ | |
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \ | |
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \ | |
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \ | |
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_TIME)) || \ | |
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME)) || \ | |
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_TIME)) | |
# include <time.h> | |
#endif | |
#if \ | |
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) || \ | |
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) || \ | |
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) | |
# include <sys/time.h> | |
#endif | |
#if \ | |
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \ | |
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \ | |
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \ | |
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \ | |
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \ | |
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) | |
typedef struct _FILETIME { | |
uint32_t dwLowDateTime; | |
uint32_t dwHighDateTime; | |
} FILETIME; | |
typedef union _LARGE_INTEGER { | |
struct { | |
uint32_t LowPart; | |
int32_t HighPart; | |
}; | |
struct { | |
uint32_t LowPart; | |
int32_t HighPart; | |
} u; | |
int64_t QuadPart; | |
} LARGE_INTEGER; | |
#ifdef __cplusplus | |
#define PSNIP_EXTERN extern "C" | |
#else | |
#define PSNIP_EXTERN | |
#endif | |
PSNIP_EXTERN void * __stdcall GetCurrentProcess(void); | |
PSNIP_EXTERN int __stdcall QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); | |
PSNIP_EXTERN int __stdcall QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); | |
PSNIP_EXTERN int __stdcall GetProcessTimes( | |
void *hProcess, | |
FILETIME *lpCreationTime, | |
FILETIME *lpExitTime, | |
FILETIME *lpKernelTime, | |
FILETIME *lpUserTime | |
); | |
#endif | |
#if \ | |
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) || \ | |
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) || \ | |
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) | |
# include <sys/time.h> | |
# include <sys/resource.h> | |
#endif | |
#if \ | |
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \ | |
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \ | |
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) | |
# include <CoreServices/CoreServices.h> | |
# include <mach/mach.h> | |
# include <mach/mach_time.h> | |
#endif | |
/*** Implementations ***/ | |
#define PSNIP_CLOCK_NSEC_PER_SEC ((uint32_t) (1000000000ULL)) | |
#if \ | |
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \ | |
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \ | |
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) | |
PSNIP_CLOCK__FUNCTION uint32_t | |
psnip_clock__clock_getres (clockid_t clk_id) { | |
struct timespec res; | |
int r; | |
r = clock_getres(clk_id, &res); | |
if (r != 0) | |
return 0; | |
return (uint32_t) (PSNIP_CLOCK_NSEC_PER_SEC / res.tv_nsec); | |
} | |
PSNIP_CLOCK__FUNCTION int | |
psnip_clock__clock_gettime (clockid_t clk_id, struct PsnipClockTimespec* res) { | |
struct timespec ts; | |
if (clock_gettime(clk_id, &ts) != 0) | |
return -10; | |
res->seconds = (uint64_t) (ts.tv_sec); | |
res->nanoseconds = (uint64_t) (ts.tv_nsec); | |
return 0; | |
} | |
#endif | |
PSNIP_CLOCK__FUNCTION uint32_t | |
psnip_clock_wall_get_precision (void) { | |
#if !defined(PSNIP_CLOCK_WALL_METHOD) | |
return 0; | |
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_WALL); | |
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY | |
return 1000000; | |
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME | |
return 1; | |
#else | |
return 0; | |
#endif | |
} | |
PSNIP_CLOCK__FUNCTION int | |
psnip_clock_wall_get_time (struct PsnipClockTimespec* res) { | |
(void) res; | |
#if !defined(PSNIP_CLOCK_WALL_METHOD) | |
return -2; | |
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_WALL, res); | |
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME | |
res->seconds = time(NULL); | |
res->nanoseconds = 0; | |
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY | |
struct timeval tv; | |
if (gettimeofday(&tv, NULL) != 0) | |
return -6; | |
res->seconds = tv.tv_sec; | |
res->nanoseconds = tv.tv_usec * 1000; | |
#else | |
return -2; | |
#endif | |
return 0; | |
} | |
PSNIP_CLOCK__FUNCTION uint32_t | |
psnip_clock_cpu_get_precision (void) { | |
#if !defined(PSNIP_CLOCK_CPU_METHOD) | |
return 0; | |
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_CPU); | |
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK | |
return CLOCKS_PER_SEC; | |
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES | |
return PSNIP_CLOCK_NSEC_PER_SEC / 100; | |
#else | |
return 0; | |
#endif | |
} | |
PSNIP_CLOCK__FUNCTION int | |
psnip_clock_cpu_get_time (struct PsnipClockTimespec* res) { | |
#if !defined(PSNIP_CLOCK_CPU_METHOD) | |
(void) res; | |
return -2; | |
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_CPU, res); | |
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK | |
clock_t t = clock(); | |
if (t == ((clock_t) -1)) | |
return -5; | |
res->seconds = t / CLOCKS_PER_SEC; | |
res->nanoseconds = (t % CLOCKS_PER_SEC) * (PSNIP_CLOCK_NSEC_PER_SEC / CLOCKS_PER_SEC); | |
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES | |
FILETIME CreationTime, ExitTime, KernelTime, UserTime; | |
LARGE_INTEGER date, adjust; | |
if (!GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime)) | |
return -7; | |
/* http://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ */ | |
date.HighPart = UserTime.dwHighDateTime; | |
date.LowPart = UserTime.dwLowDateTime; | |
adjust.QuadPart = 11644473600000 * 10000; | |
date.QuadPart -= adjust.QuadPart; | |
res->seconds = date.QuadPart / 10000000; | |
res->nanoseconds = (date.QuadPart % 10000000) * (PSNIP_CLOCK_NSEC_PER_SEC / 100); | |
#elif PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE | |
struct rusage usage; | |
if (getrusage(RUSAGE_SELF, &usage) != 0) | |
return -8; | |
res->seconds = usage.ru_utime.tv_sec; | |
res->nanoseconds = tv.tv_usec * 1000; | |
#else | |
(void) res; | |
return -2; | |
#endif | |
return 0; | |
} | |
PSNIP_CLOCK__FUNCTION uint32_t | |
psnip_clock_monotonic_get_precision (void) { | |
#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) | |
return 0; | |
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC); | |
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME | |
static mach_timebase_info_data_t tbi = { 0, }; | |
if (tbi.denom == 0) | |
mach_timebase_info(&tbi); | |
return (uint32_t) (tbi.numer / tbi.denom); | |
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64 | |
return 1000; | |
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER | |
LARGE_INTEGER Frequency; | |
QueryPerformanceFrequency(&Frequency); | |
return (uint32_t) ((Frequency.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC) ? PSNIP_CLOCK_NSEC_PER_SEC : Frequency.QuadPart); | |
#else | |
return 0; | |
#endif | |
} | |
PSNIP_CLOCK__FUNCTION int | |
psnip_clock_monotonic_get_time (struct PsnipClockTimespec* res) { | |
#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) | |
(void) res; | |
return -2; | |
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME | |
return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC, res); | |
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME | |
uint64_t nsec = mach_absolute_time(); | |
static mach_timebase_info_data_t tbi = { 0, }; | |
if (tbi.denom == 0) | |
mach_timebase_info(&tbi); | |
nsec *= ((uint64_t) tbi.numer) / ((uint64_t) tbi.denom); | |
res->seconds = nsec / PSNIP_CLOCK_NSEC_PER_SEC; | |
res->nanoseconds = nsec % PSNIP_CLOCK_NSEC_PER_SEC; | |
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER | |
LARGE_INTEGER t, f; | |
if (QueryPerformanceCounter(&t) == 0) | |
return -12; | |
QueryPerformanceFrequency(&f); | |
res->seconds = t.QuadPart / f.QuadPart; | |
res->nanoseconds = t.QuadPart % f.QuadPart; | |
if (f.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC) | |
res->nanoseconds /= f.QuadPart / PSNIP_CLOCK_NSEC_PER_SEC; | |
else | |
res->nanoseconds *= PSNIP_CLOCK_NSEC_PER_SEC / f.QuadPart; | |
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64 | |
const ULONGLONG msec = GetTickCount64(); | |
res->seconds = msec / 1000; | |
res->nanoseconds = sec % 1000; | |
#else | |
return -2; | |
#endif | |
return 0; | |
} | |
/* Returns the number of ticks per second for the specified clock. | |
* For example, a clock with millisecond precision would return 1000, | |
* and a clock with 1 second (such as the time() function) would | |
* return 1. | |
* | |
* If the requested clock isn't available, it will return 0. | |
* Hopefully this will be rare, but if it happens to you please let us | |
* know so we can work on finding a way to support your system. | |
* | |
* Note that different clocks on the same system often have a | |
* different precisions. | |
*/ | |
PSNIP_CLOCK__FUNCTION uint32_t | |
psnip_clock_get_precision (enum PsnipClockType clock_type) { | |
switch (clock_type) { | |
case PSNIP_CLOCK_TYPE_MONOTONIC: | |
return psnip_clock_monotonic_get_precision (); | |
case PSNIP_CLOCK_TYPE_CPU: | |
return psnip_clock_cpu_get_precision (); | |
case PSNIP_CLOCK_TYPE_WALL: | |
return psnip_clock_wall_get_precision (); | |
} | |
PSNIP_CLOCK_UNREACHABLE(); | |
return 0; | |
} | |
/* Set the provided timespec to the requested time. Returns 0 on | |
* success, or a negative value on failure. */ | |
PSNIP_CLOCK__FUNCTION int | |
psnip_clock_get_time (enum PsnipClockType clock_type, struct PsnipClockTimespec* res) { | |
assert(res != NULL); | |
switch (clock_type) { | |
case PSNIP_CLOCK_TYPE_MONOTONIC: | |
return psnip_clock_monotonic_get_time (res); | |
case PSNIP_CLOCK_TYPE_CPU: | |
return psnip_clock_cpu_get_time (res); | |
case PSNIP_CLOCK_TYPE_WALL: | |
return psnip_clock_wall_get_time (res); | |
} | |
return -1; | |
} | |
#endif /* !defined(PSNIP_CLOCK_H) */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment