478 lines
18 KiB
C
478 lines
18 KiB
C
/* Clocks (v1)
|
|
* Portable Snippets - https://github.com/nemequ/portable-snippets
|
|
* Created by Evan Nemerson <evan@nemerson.com>
|
|
*
|
|
* 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) */
|