blob: 29b849e6ce02e73ed02d8d939902c0e848bc8c46 [file] [log] [blame]
Vladimir Marko80afd022015-05-19 18:08:00 +01001/*
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 <inttypes.h>
18#include <sstream>
19
20#include "time_utils.h"
21
22#include "base/logging.h"
23#include "base/stringprintf.h"
24
25namespace art {
26
27std::string PrettyDuration(uint64_t nano_duration, size_t max_fraction_digits) {
28 if (nano_duration == 0) {
29 return "0";
30 } else {
31 return FormatDuration(nano_duration, GetAppropriateTimeUnit(nano_duration),
32 max_fraction_digits);
33 }
34}
35
36TimeUnit GetAppropriateTimeUnit(uint64_t nano_duration) {
37 const uint64_t one_sec = 1000 * 1000 * 1000;
38 const uint64_t one_ms = 1000 * 1000;
39 const uint64_t one_us = 1000;
40 if (nano_duration >= one_sec) {
41 return kTimeUnitSecond;
42 } else if (nano_duration >= one_ms) {
43 return kTimeUnitMillisecond;
44 } else if (nano_duration >= one_us) {
45 return kTimeUnitMicrosecond;
46 } else {
47 return kTimeUnitNanosecond;
48 }
49}
50
51uint64_t GetNsToTimeUnitDivisor(TimeUnit time_unit) {
52 const uint64_t one_sec = 1000 * 1000 * 1000;
53 const uint64_t one_ms = 1000 * 1000;
54 const uint64_t one_us = 1000;
55
56 switch (time_unit) {
57 case kTimeUnitSecond:
58 return one_sec;
59 case kTimeUnitMillisecond:
60 return one_ms;
61 case kTimeUnitMicrosecond:
62 return one_us;
63 case kTimeUnitNanosecond:
64 return 1;
65 }
66 return 0;
67}
68
69std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit,
70 size_t max_fraction_digits) {
71 const char* unit = nullptr;
72 uint64_t divisor = GetNsToTimeUnitDivisor(time_unit);
73 switch (time_unit) {
74 case kTimeUnitSecond:
75 unit = "s";
76 break;
77 case kTimeUnitMillisecond:
78 unit = "ms";
79 break;
80 case kTimeUnitMicrosecond:
81 unit = "us";
82 break;
83 case kTimeUnitNanosecond:
84 unit = "ns";
85 break;
86 }
87 const uint64_t whole_part = nano_duration / divisor;
88 uint64_t fractional_part = nano_duration % divisor;
89 if (fractional_part == 0) {
90 return StringPrintf("%" PRIu64 "%s", whole_part, unit);
91 } else {
92 static constexpr size_t kMaxDigits = 30;
93 size_t avail_digits = kMaxDigits;
94 char fraction_buffer[kMaxDigits];
95 char* ptr = fraction_buffer;
96 uint64_t multiplier = 10;
97 // This infinite loops if fractional part is 0.
98 while (avail_digits > 1 && fractional_part * multiplier < divisor) {
99 multiplier *= 10;
100 *ptr++ = '0';
101 avail_digits--;
102 }
103 snprintf(ptr, avail_digits, "%" PRIu64, fractional_part);
104 fraction_buffer[std::min(kMaxDigits - 1, max_fraction_digits)] = '\0';
105 return StringPrintf("%" PRIu64 ".%s%s", whole_part, fraction_buffer, unit);
106 }
107}
108
109std::string GetIsoDate() {
110 time_t now = time(nullptr);
111 tm tmbuf;
112 tm* ptm = localtime_r(&now, &tmbuf);
113 return StringPrintf("%04d-%02d-%02d %02d:%02d:%02d",
114 ptm->tm_year + 1900, ptm->tm_mon+1, ptm->tm_mday,
115 ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
116}
117
118uint64_t MilliTime() {
119#if defined(__linux__)
120 timespec now;
121 clock_gettime(CLOCK_MONOTONIC, &now);
122 return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_nsec / UINT64_C(1000000);
123#else // __APPLE__
124 timeval now;
125 gettimeofday(&now, nullptr);
126 return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_usec / UINT64_C(1000);
127#endif
128}
129
130uint64_t MicroTime() {
131#if defined(__linux__)
132 timespec now;
133 clock_gettime(CLOCK_MONOTONIC, &now);
134 return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_nsec / UINT64_C(1000);
135#else // __APPLE__
136 timeval now;
137 gettimeofday(&now, nullptr);
138 return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_usec;
139#endif
140}
141
142uint64_t NanoTime() {
143#if defined(__linux__)
144 timespec now;
145 clock_gettime(CLOCK_MONOTONIC, &now);
146 return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
147#else // __APPLE__
148 timeval now;
149 gettimeofday(&now, nullptr);
150 return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_usec * UINT64_C(1000);
151#endif
152}
153
154uint64_t ThreadCpuNanoTime() {
155#if defined(__linux__)
156 timespec now;
157 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
158 return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
159#else // __APPLE__
160 UNIMPLEMENTED(WARNING);
161 return -1;
162#endif
163}
164
165void NanoSleep(uint64_t ns) {
166 timespec tm;
167 tm.tv_sec = ns / MsToNs(1000);
168 tm.tv_nsec = ns - static_cast<uint64_t>(tm.tv_sec) * MsToNs(1000);
169 nanosleep(&tm, nullptr);
170}
171
172void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts) {
173 int64_t endSec;
174
175 if (absolute) {
176#if !defined(__APPLE__)
177 clock_gettime(clock, ts);
178#else
179 UNUSED(clock);
180 timeval tv;
181 gettimeofday(&tv, nullptr);
182 ts->tv_sec = tv.tv_sec;
183 ts->tv_nsec = tv.tv_usec * 1000;
184#endif
185 } else {
186 ts->tv_sec = 0;
187 ts->tv_nsec = 0;
188 }
189 endSec = ts->tv_sec + ms / 1000;
190 if (UNLIKELY(endSec >= 0x7fffffff)) {
191 std::ostringstream ss;
192 LOG(INFO) << "Note: end time exceeds epoch: " << ss.str();
193 endSec = 0x7ffffffe;
194 }
195 ts->tv_sec = endSec;
196 ts->tv_nsec = (ts->tv_nsec + (ms % 1000) * 1000000) + ns;
197
198 // Catch rollover.
199 if (ts->tv_nsec >= 1000000000L) {
200 ts->tv_sec++;
201 ts->tv_nsec -= 1000000000L;
202 }
203}
204
205} // namespace art