Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "time_utils.h"
     18 
     19 #include <inttypes.h>
     20 #include <stdio.h>
     21 
     22 #include <limits>
     23 #include <sstream>
     24 
     25 #include "android-base/stringprintf.h"
     26 
     27 #include "logging.h"
     28 
     29 #if defined(__APPLE__)
     30 #include <sys/time.h>
     31 #endif
     32 
     33 namespace art {
     34 
     35 namespace {
     36 
     37 #if !defined(__linux__)
     38 int GetTimeOfDay(struct timeval* tv, struct timezone* tz) {
     39 #ifdef _WIN32
     40   return mingw_gettimeofday(tv, tz);
     41 #else
     42   return gettimeofday(tv, tz);
     43 #endif
     44 }
     45 #endif
     46 
     47 }  // namespace
     48 
     49 using android::base::StringPrintf;
     50 
     51 std::string PrettyDuration(uint64_t nano_duration, size_t max_fraction_digits) {
     52   if (nano_duration == 0) {
     53     return "0";
     54   } else {
     55     return FormatDuration(nano_duration, GetAppropriateTimeUnit(nano_duration),
     56                           max_fraction_digits);
     57   }
     58 }
     59 
     60 TimeUnit GetAppropriateTimeUnit(uint64_t nano_duration) {
     61   const uint64_t one_sec = 1000 * 1000 * 1000;
     62   const uint64_t one_ms  = 1000 * 1000;
     63   const uint64_t one_us  = 1000;
     64   if (nano_duration >= one_sec) {
     65     return kTimeUnitSecond;
     66   } else if (nano_duration >= one_ms) {
     67     return kTimeUnitMillisecond;
     68   } else if (nano_duration >= one_us) {
     69     return kTimeUnitMicrosecond;
     70   } else {
     71     return kTimeUnitNanosecond;
     72   }
     73 }
     74 
     75 uint64_t GetNsToTimeUnitDivisor(TimeUnit time_unit) {
     76   const uint64_t one_sec = 1000 * 1000 * 1000;
     77   const uint64_t one_ms  = 1000 * 1000;
     78   const uint64_t one_us  = 1000;
     79 
     80   switch (time_unit) {
     81     case kTimeUnitSecond:
     82       return one_sec;
     83     case kTimeUnitMillisecond:
     84       return one_ms;
     85     case kTimeUnitMicrosecond:
     86       return one_us;
     87     case kTimeUnitNanosecond:
     88       return 1;
     89   }
     90   return 0;
     91 }
     92 
     93 std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit,
     94                            size_t max_fraction_digits) {
     95   const char* unit = nullptr;
     96   uint64_t divisor = GetNsToTimeUnitDivisor(time_unit);
     97   switch (time_unit) {
     98     case kTimeUnitSecond:
     99       unit = "s";
    100       break;
    101     case kTimeUnitMillisecond:
    102       unit = "ms";
    103       break;
    104     case kTimeUnitMicrosecond:
    105       unit = "us";
    106       break;
    107     case kTimeUnitNanosecond:
    108       unit = "ns";
    109       break;
    110   }
    111   const uint64_t whole_part = nano_duration / divisor;
    112   uint64_t fractional_part = nano_duration % divisor;
    113   if (fractional_part == 0) {
    114     return StringPrintf("%" PRIu64 "%s", whole_part, unit);
    115   } else {
    116     static constexpr size_t kMaxDigits = 30;
    117     size_t avail_digits = kMaxDigits;
    118     char fraction_buffer[kMaxDigits];
    119     char* ptr = fraction_buffer;
    120     uint64_t multiplier = 10;
    121     // This infinite loops if fractional part is 0.
    122     while (avail_digits > 1 && fractional_part * multiplier < divisor) {
    123       multiplier *= 10;
    124       *ptr++ = '0';
    125       avail_digits--;
    126     }
    127     snprintf(ptr, avail_digits, "%" PRIu64, fractional_part);
    128     fraction_buffer[std::min(kMaxDigits - 1, max_fraction_digits)] = '\0';
    129     return StringPrintf("%" PRIu64 ".%s%s", whole_part, fraction_buffer, unit);
    130   }
    131 }
    132 
    133 std::string GetIsoDate() {
    134   time_t now = time(nullptr);
    135   tm tmbuf;
    136 #ifdef _WIN32
    137   localtime_s(&tmbuf, &now);
    138   tm* ptm = &tmbuf;
    139 #else
    140   tm* ptm = localtime_r(&now, &tmbuf);
    141 #endif
    142   return StringPrintf("%04d-%02d-%02d %02d:%02d:%02d",
    143       ptm->tm_year + 1900, ptm->tm_mon+1, ptm->tm_mday,
    144       ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    145 }
    146 
    147 uint64_t MilliTime() {
    148 #if defined(__linux__)
    149   timespec now;
    150   clock_gettime(CLOCK_MONOTONIC, &now);
    151   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_nsec / UINT64_C(1000000);
    152 #else
    153   timeval now;
    154   GetTimeOfDay(&now, nullptr);
    155   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_usec / UINT64_C(1000);
    156 #endif
    157 }
    158 
    159 uint64_t MicroTime() {
    160 #if defined(__linux__)
    161   timespec now;
    162   clock_gettime(CLOCK_MONOTONIC, &now);
    163   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_nsec / UINT64_C(1000);
    164 #else
    165   timeval now;
    166   GetTimeOfDay(&now, nullptr);
    167   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_usec;
    168 #endif
    169 }
    170 
    171 uint64_t NanoTime() {
    172 #if defined(__linux__)
    173   timespec now;
    174   clock_gettime(CLOCK_MONOTONIC, &now);
    175   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
    176 #else
    177   timeval now;
    178   GetTimeOfDay(&now, nullptr);
    179   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_usec * UINT64_C(1000);
    180 #endif
    181 }
    182 
    183 uint64_t ThreadCpuNanoTime() {
    184 #if defined(__linux__)
    185   timespec now;
    186   clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
    187   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
    188 #else
    189   UNIMPLEMENTED(WARNING);
    190   return -1;
    191 #endif
    192 }
    193 
    194 uint64_t ProcessCpuNanoTime() {
    195 #if defined(__linux__)
    196   timespec now;
    197   clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &now);
    198   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
    199 #else
    200   // We cannot use clock_gettime() here. Return the process wall clock time
    201   // (using art::NanoTime, which relies on gettimeofday()) as approximation of
    202   // the process CPU time instead.
    203   //
    204   // Note: clock_gettime() is available from macOS 10.12 (Darwin 16), but we try
    205   // to keep things simple here.
    206   return NanoTime();
    207 #endif
    208 }
    209 
    210 void NanoSleep(uint64_t ns) {
    211   timespec tm;
    212   tm.tv_sec = ns / MsToNs(1000);
    213   tm.tv_nsec = ns - static_cast<uint64_t>(tm.tv_sec) * MsToNs(1000);
    214   nanosleep(&tm, nullptr);
    215 }
    216 
    217 void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts) {
    218   if (absolute) {
    219 #if defined(__linux__)
    220     clock_gettime(clock, ts);
    221 #else
    222     UNUSED(clock);
    223     timeval tv;
    224     GetTimeOfDay(&tv, nullptr);
    225     ts->tv_sec = tv.tv_sec;
    226     ts->tv_nsec = tv.tv_usec * 1000;
    227 #endif
    228   } else {
    229     ts->tv_sec = 0;
    230     ts->tv_nsec = 0;
    231   }
    232 
    233   int64_t end_sec = ts->tv_sec + ms / 1000;
    234   constexpr int32_t int32_max = std::numeric_limits<int32_t>::max();
    235   if (UNLIKELY(end_sec >= int32_max)) {
    236     // Either ms was intended to denote an infinite timeout, or we have a
    237     // problem. The former generally uses the largest possible millisecond
    238     // or nanosecond value.  Log only in the latter case.
    239     constexpr int64_t int64_max = std::numeric_limits<int64_t>::max();
    240     if (ms != int64_max && ms != int64_max / (1000 * 1000)) {
    241       LOG(INFO) << "Note: end time exceeds INT32_MAX: " << end_sec;
    242     }
    243     end_sec = int32_max - 1;  // Allow for increment below.
    244   }
    245   ts->tv_sec = end_sec;
    246   ts->tv_nsec = (ts->tv_nsec + (ms % 1000) * 1000000) + ns;
    247 
    248   // Catch rollover.
    249   if (ts->tv_nsec >= 1000000000L) {
    250     ts->tv_sec++;
    251     ts->tv_nsec -= 1000000000L;
    252   }
    253 }
    254 
    255 }  // namespace art
    256