1*2b9c00cbSConrad Meyer /* 2*2b9c00cbSConrad Meyer * Copyright (c) 2019-present, Yann Collet, Facebook, Inc. 3*2b9c00cbSConrad Meyer * All rights reserved. 4*2b9c00cbSConrad Meyer * 5*2b9c00cbSConrad Meyer * This source code is licensed under both the BSD-style license (found in the 6*2b9c00cbSConrad Meyer * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*2b9c00cbSConrad Meyer * in the COPYING file in the root directory of this source tree). 8*2b9c00cbSConrad Meyer * You may select, at your option, one of the above-listed licenses. 9*2b9c00cbSConrad Meyer */ 10*2b9c00cbSConrad Meyer 11*2b9c00cbSConrad Meyer 12*2b9c00cbSConrad Meyer /* === Dependencies === */ 13*2b9c00cbSConrad Meyer 14*2b9c00cbSConrad Meyer #include "timefn.h" 15*2b9c00cbSConrad Meyer 16*2b9c00cbSConrad Meyer 17*2b9c00cbSConrad Meyer /*-**************************************** 18*2b9c00cbSConrad Meyer * Time functions 19*2b9c00cbSConrad Meyer ******************************************/ 20*2b9c00cbSConrad Meyer 21*2b9c00cbSConrad Meyer #if defined(_WIN32) /* Windows */ 22*2b9c00cbSConrad Meyer 23*2b9c00cbSConrad Meyer #include <stdlib.h> /* abort */ 24*2b9c00cbSConrad Meyer #include <stdio.h> /* perror */ 25*2b9c00cbSConrad Meyer 26*2b9c00cbSConrad Meyer UTIL_time_t UTIL_getTime(void) { UTIL_time_t x; QueryPerformanceCounter(&x); return x; } 27*2b9c00cbSConrad Meyer 28*2b9c00cbSConrad Meyer PTime UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) 29*2b9c00cbSConrad Meyer { 30*2b9c00cbSConrad Meyer static LARGE_INTEGER ticksPerSecond; 31*2b9c00cbSConrad Meyer static int init = 0; 32*2b9c00cbSConrad Meyer if (!init) { 33*2b9c00cbSConrad Meyer if (!QueryPerformanceFrequency(&ticksPerSecond)) { 34*2b9c00cbSConrad Meyer perror("timefn::QueryPerformanceFrequency"); 35*2b9c00cbSConrad Meyer abort(); 36*2b9c00cbSConrad Meyer } 37*2b9c00cbSConrad Meyer init = 1; 38*2b9c00cbSConrad Meyer } 39*2b9c00cbSConrad Meyer return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; 40*2b9c00cbSConrad Meyer } 41*2b9c00cbSConrad Meyer 42*2b9c00cbSConrad Meyer PTime UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) 43*2b9c00cbSConrad Meyer { 44*2b9c00cbSConrad Meyer static LARGE_INTEGER ticksPerSecond; 45*2b9c00cbSConrad Meyer static int init = 0; 46*2b9c00cbSConrad Meyer if (!init) { 47*2b9c00cbSConrad Meyer if (!QueryPerformanceFrequency(&ticksPerSecond)) { 48*2b9c00cbSConrad Meyer perror("timefn::QueryPerformanceFrequency"); 49*2b9c00cbSConrad Meyer abort(); 50*2b9c00cbSConrad Meyer } 51*2b9c00cbSConrad Meyer init = 1; 52*2b9c00cbSConrad Meyer } 53*2b9c00cbSConrad Meyer return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; 54*2b9c00cbSConrad Meyer } 55*2b9c00cbSConrad Meyer 56*2b9c00cbSConrad Meyer 57*2b9c00cbSConrad Meyer 58*2b9c00cbSConrad Meyer #elif defined(__APPLE__) && defined(__MACH__) 59*2b9c00cbSConrad Meyer 60*2b9c00cbSConrad Meyer UTIL_time_t UTIL_getTime(void) { return mach_absolute_time(); } 61*2b9c00cbSConrad Meyer 62*2b9c00cbSConrad Meyer PTime UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) 63*2b9c00cbSConrad Meyer { 64*2b9c00cbSConrad Meyer static mach_timebase_info_data_t rate; 65*2b9c00cbSConrad Meyer static int init = 0; 66*2b9c00cbSConrad Meyer if (!init) { 67*2b9c00cbSConrad Meyer mach_timebase_info(&rate); 68*2b9c00cbSConrad Meyer init = 1; 69*2b9c00cbSConrad Meyer } 70*2b9c00cbSConrad Meyer return (((clockEnd - clockStart) * (PTime)rate.numer) / ((PTime)rate.denom))/1000ULL; 71*2b9c00cbSConrad Meyer } 72*2b9c00cbSConrad Meyer 73*2b9c00cbSConrad Meyer PTime UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) 74*2b9c00cbSConrad Meyer { 75*2b9c00cbSConrad Meyer static mach_timebase_info_data_t rate; 76*2b9c00cbSConrad Meyer static int init = 0; 77*2b9c00cbSConrad Meyer if (!init) { 78*2b9c00cbSConrad Meyer mach_timebase_info(&rate); 79*2b9c00cbSConrad Meyer init = 1; 80*2b9c00cbSConrad Meyer } 81*2b9c00cbSConrad Meyer return ((clockEnd - clockStart) * (PTime)rate.numer) / ((PTime)rate.denom); 82*2b9c00cbSConrad Meyer } 83*2b9c00cbSConrad Meyer 84*2b9c00cbSConrad Meyer 85*2b9c00cbSConrad Meyer 86*2b9c00cbSConrad Meyer #elif (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */) \ 87*2b9c00cbSConrad Meyer && defined(TIME_UTC) /* C11 requires timespec_get, but FreeBSD 11 lacks it, while still claiming C11 compliance */ 88*2b9c00cbSConrad Meyer 89*2b9c00cbSConrad Meyer #include <stdlib.h> /* abort */ 90*2b9c00cbSConrad Meyer #include <stdio.h> /* perror */ 91*2b9c00cbSConrad Meyer 92*2b9c00cbSConrad Meyer UTIL_time_t UTIL_getTime(void) 93*2b9c00cbSConrad Meyer { 94*2b9c00cbSConrad Meyer /* time must be initialized, othersize it may fail msan test. 95*2b9c00cbSConrad Meyer * No good reason, likely a limitation of timespec_get() for some target */ 96*2b9c00cbSConrad Meyer UTIL_time_t time = UTIL_TIME_INITIALIZER; 97*2b9c00cbSConrad Meyer if (timespec_get(&time, TIME_UTC) != TIME_UTC) { 98*2b9c00cbSConrad Meyer perror("timefn::timespec_get"); 99*2b9c00cbSConrad Meyer abort(); 100*2b9c00cbSConrad Meyer } 101*2b9c00cbSConrad Meyer return time; 102*2b9c00cbSConrad Meyer } 103*2b9c00cbSConrad Meyer 104*2b9c00cbSConrad Meyer static UTIL_time_t UTIL_getSpanTime(UTIL_time_t begin, UTIL_time_t end) 105*2b9c00cbSConrad Meyer { 106*2b9c00cbSConrad Meyer UTIL_time_t diff; 107*2b9c00cbSConrad Meyer if (end.tv_nsec < begin.tv_nsec) { 108*2b9c00cbSConrad Meyer diff.tv_sec = (end.tv_sec - 1) - begin.tv_sec; 109*2b9c00cbSConrad Meyer diff.tv_nsec = (end.tv_nsec + 1000000000ULL) - begin.tv_nsec; 110*2b9c00cbSConrad Meyer } else { 111*2b9c00cbSConrad Meyer diff.tv_sec = end.tv_sec - begin.tv_sec; 112*2b9c00cbSConrad Meyer diff.tv_nsec = end.tv_nsec - begin.tv_nsec; 113*2b9c00cbSConrad Meyer } 114*2b9c00cbSConrad Meyer return diff; 115*2b9c00cbSConrad Meyer } 116*2b9c00cbSConrad Meyer 117*2b9c00cbSConrad Meyer PTime UTIL_getSpanTimeMicro(UTIL_time_t begin, UTIL_time_t end) 118*2b9c00cbSConrad Meyer { 119*2b9c00cbSConrad Meyer UTIL_time_t const diff = UTIL_getSpanTime(begin, end); 120*2b9c00cbSConrad Meyer PTime micro = 0; 121*2b9c00cbSConrad Meyer micro += 1000000ULL * diff.tv_sec; 122*2b9c00cbSConrad Meyer micro += diff.tv_nsec / 1000ULL; 123*2b9c00cbSConrad Meyer return micro; 124*2b9c00cbSConrad Meyer } 125*2b9c00cbSConrad Meyer 126*2b9c00cbSConrad Meyer PTime UTIL_getSpanTimeNano(UTIL_time_t begin, UTIL_time_t end) 127*2b9c00cbSConrad Meyer { 128*2b9c00cbSConrad Meyer UTIL_time_t const diff = UTIL_getSpanTime(begin, end); 129*2b9c00cbSConrad Meyer PTime nano = 0; 130*2b9c00cbSConrad Meyer nano += 1000000000ULL * diff.tv_sec; 131*2b9c00cbSConrad Meyer nano += diff.tv_nsec; 132*2b9c00cbSConrad Meyer return nano; 133*2b9c00cbSConrad Meyer } 134*2b9c00cbSConrad Meyer 135*2b9c00cbSConrad Meyer 136*2b9c00cbSConrad Meyer 137*2b9c00cbSConrad Meyer #else /* relies on standard C90 (note : clock_t measurements can be wrong when using multi-threading) */ 138*2b9c00cbSConrad Meyer 139*2b9c00cbSConrad Meyer UTIL_time_t UTIL_getTime(void) { return clock(); } 140*2b9c00cbSConrad Meyer PTime UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } 141*2b9c00cbSConrad Meyer PTime UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } 142*2b9c00cbSConrad Meyer 143*2b9c00cbSConrad Meyer #endif 144*2b9c00cbSConrad Meyer 145*2b9c00cbSConrad Meyer 146*2b9c00cbSConrad Meyer 147*2b9c00cbSConrad Meyer /* returns time span in microseconds */ 148*2b9c00cbSConrad Meyer PTime UTIL_clockSpanMicro(UTIL_time_t clockStart ) 149*2b9c00cbSConrad Meyer { 150*2b9c00cbSConrad Meyer UTIL_time_t const clockEnd = UTIL_getTime(); 151*2b9c00cbSConrad Meyer return UTIL_getSpanTimeMicro(clockStart, clockEnd); 152*2b9c00cbSConrad Meyer } 153*2b9c00cbSConrad Meyer 154*2b9c00cbSConrad Meyer /* returns time span in microseconds */ 155*2b9c00cbSConrad Meyer PTime UTIL_clockSpanNano(UTIL_time_t clockStart ) 156*2b9c00cbSConrad Meyer { 157*2b9c00cbSConrad Meyer UTIL_time_t const clockEnd = UTIL_getTime(); 158*2b9c00cbSConrad Meyer return UTIL_getSpanTimeNano(clockStart, clockEnd); 159*2b9c00cbSConrad Meyer } 160*2b9c00cbSConrad Meyer 161*2b9c00cbSConrad Meyer void UTIL_waitForNextTick(void) 162*2b9c00cbSConrad Meyer { 163*2b9c00cbSConrad Meyer UTIL_time_t const clockStart = UTIL_getTime(); 164*2b9c00cbSConrad Meyer UTIL_time_t clockEnd; 165*2b9c00cbSConrad Meyer do { 166*2b9c00cbSConrad Meyer clockEnd = UTIL_getTime(); 167*2b9c00cbSConrad Meyer } while (UTIL_getSpanTimeNano(clockStart, clockEnd) == 0); 168*2b9c00cbSConrad Meyer } 169