Home | History | Annotate | Line # | Download | only in programs
      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