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