1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18// Date: Wed Aug 11 10:38:17 2010
19
20// Measuring time
21
22#ifndef BUTIL_BAIDU_TIME_H
23#define BUTIL_BAIDU_TIME_H
24
25#include <time.h> // timespec, clock_gettime
26#include <sys/time.h> // timeval, gettimeofday
27#include <stdint.h> // int64_t, uint64_t
28
29#if defined(NO_CLOCK_GETTIME_IN_MAC)
30#include <mach/mach.h>
31# define CLOCK_REALTIME CALENDAR_CLOCK
32# define CLOCK_MONOTONIC SYSTEM_CLOCK
33
34typedef int clockid_t;
35
36// clock_gettime is not available in MacOS < 10.12
37int clock_gettime(clockid_t id, timespec* time);
38
39#endif
40
41namespace butil {
42
43// Get SVN revision of this copy.
44const char* last_changed_revision();
45
46// ----------------------
47// timespec manipulations
48// ----------------------
49
50// Let tm->tv_nsec be in [0, 1,000,000,000) if it's not.
51inline void timespec_normalize(timespec* tm) {
52 if (tm->tv_nsec >= 1000000000L) {
53 const int64_t added_sec = tm->tv_nsec / 1000000000L;
54 tm->tv_sec += added_sec;
55 tm->tv_nsec -= added_sec * 1000000000L;
56 } else if (tm->tv_nsec < 0) {
57 const int64_t sub_sec = (tm->tv_nsec - 999999999L) / 1000000000L;
58 tm->tv_sec += sub_sec;
59 tm->tv_nsec -= sub_sec * 1000000000L;
60 }
61}
62
63// Add timespec |span| into timespec |*tm|.
64inline void timespec_add(timespec *tm, const timespec& span) {
65 tm->tv_sec += span.tv_sec;
66 tm->tv_nsec += span.tv_nsec;
67 timespec_normalize(tm);
68}
69
70// Minus timespec |span| from timespec |*tm|.
71// tm->tv_nsec will be inside [0, 1,000,000,000)
72inline void timespec_minus(timespec *tm, const timespec& span) {
73 tm->tv_sec -= span.tv_sec;
74 tm->tv_nsec -= span.tv_nsec;
75 timespec_normalize(tm);
76}
77
78// ------------------------------------------------------------------
79// Get the timespec after specified duration from |start_time|
80// ------------------------------------------------------------------
81inline timespec nanoseconds_from(timespec start_time, int64_t nanoseconds) {
82 start_time.tv_nsec += nanoseconds;
83 timespec_normalize(&start_time);
84 return start_time;
85}
86
87inline timespec microseconds_from(timespec start_time, int64_t microseconds) {
88 return nanoseconds_from(start_time, microseconds * 1000L);
89}
90
91inline timespec milliseconds_from(timespec start_time, int64_t milliseconds) {
92 return nanoseconds_from(start_time, milliseconds * 1000000L);
93}
94
95inline timespec seconds_from(timespec start_time, int64_t seconds) {
96 return nanoseconds_from(start_time, seconds * 1000000000L);
97}
98
99// --------------------------------------------------------------------
100// Get the timespec after specified duration from now (CLOCK_REALTIME)
101// --------------------------------------------------------------------
102inline timespec nanoseconds_from_now(int64_t nanoseconds) {
103 timespec time;
104 clock_gettime(CLOCK_REALTIME, &time);
105 return nanoseconds_from(time, nanoseconds);
106}
107
108inline timespec microseconds_from_now(int64_t microseconds) {
109 return nanoseconds_from_now(microseconds * 1000L);
110}
111
112inline timespec milliseconds_from_now(int64_t milliseconds) {
113 return nanoseconds_from_now(milliseconds * 1000000L);
114}
115
116inline timespec seconds_from_now(int64_t seconds) {
117 return nanoseconds_from_now(seconds * 1000000000L);
118}
119
120inline timespec timespec_from_now(const timespec& span) {
121 timespec time;
122 clock_gettime(CLOCK_REALTIME, &time);
123 timespec_add(&time, span);
124 return time;
125}
126
127// ---------------------------------------------------------------------
128// Convert timespec to and from a single integer.
129// For conversions between timespec and timeval, use TIMEVAL_TO_TIMESPEC
130// and TIMESPEC_TO_TIMEVAL defined in <sys/time.h>
131// ---------------------------------------------------------------------1
132inline int64_t timespec_to_nanoseconds(const timespec& ts) {
133 return ts.tv_sec * 1000000000L + ts.tv_nsec;
134}
135
136inline int64_t timespec_to_microseconds(const timespec& ts) {
137 return timespec_to_nanoseconds(ts) / 1000L;
138}
139
140inline int64_t timespec_to_milliseconds(const timespec& ts) {
141 return timespec_to_nanoseconds(ts) / 1000000L;
142}
143
144inline int64_t timespec_to_seconds(const timespec& ts) {
145 return timespec_to_nanoseconds(ts) / 1000000000L;
146}
147
148inline timespec nanoseconds_to_timespec(int64_t ns) {
149 timespec ts;
150 ts.tv_sec = ns / 1000000000L;
151 ts.tv_nsec = ns - ts.tv_sec * 1000000000L;
152 return ts;
153}
154
155inline timespec microseconds_to_timespec(int64_t us) {
156 return nanoseconds_to_timespec(us * 1000L);
157}
158
159inline timespec milliseconds_to_timespec(int64_t ms) {
160 return nanoseconds_to_timespec(ms * 1000000L);
161}
162
163inline timespec seconds_to_timespec(int64_t s) {
164 return nanoseconds_to_timespec(s * 1000000000L);
165}
166
167// ---------------------------------------------------------------------
168// Convert timeval to and from a single integer.
169// For conversions between timespec and timeval, use TIMEVAL_TO_TIMESPEC
170// and TIMESPEC_TO_TIMEVAL defined in <sys/time.h>
171// ---------------------------------------------------------------------
172inline int64_t timeval_to_microseconds(const timeval& tv) {
173 return tv.tv_sec * 1000000L + tv.tv_usec;
174}
175
176inline int64_t timeval_to_milliseconds(const timeval& tv) {
177 return timeval_to_microseconds(tv) / 1000L;
178}
179
180inline int64_t timeval_to_seconds(const timeval& tv) {
181 return timeval_to_microseconds(tv) / 1000000L;
182}
183
184inline timeval microseconds_to_timeval(int64_t us) {
185 timeval tv;
186 tv.tv_sec = us / 1000000L;
187 tv.tv_usec = us - tv.tv_sec * 1000000L;
188 return tv;
189}
190
191inline timeval milliseconds_to_timeval(int64_t ms) {
192 return microseconds_to_timeval(ms * 1000L);
193}
194
195inline timeval seconds_to_timeval(int64_t s) {
196 return microseconds_to_timeval(s * 1000000L);
197}
198
199// ---------------------------------------------------------------
200// Get system-wide monotonic time.
201// ---------------------------------------------------------------
202extern int64_t monotonic_time_ns();
203
204inline int64_t monotonic_time_us() {
205 return monotonic_time_ns() / 1000L;
206}
207
208inline int64_t monotonic_time_ms() {
209 return monotonic_time_ns() / 1000000L;
210}
211
212inline int64_t monotonic_time_s() {
213 return monotonic_time_ns() / 1000000000L;
214}
215
216namespace detail {
217inline uint64_t clock_cycles() {
218 unsigned int lo = 0;
219 unsigned int hi = 0;
220 // We cannot use "=A", since this would use %rax on x86_64
221 __asm__ __volatile__ (
222 "rdtsc"
223 : "=a" (lo), "=d" (hi)
224 );
225 return ((uint64_t)hi << 32) | lo;
226}
227extern int64_t read_invariant_cpu_frequency();
228// Be positive iff:
229// 1 Intel x86_64 CPU (multiple cores) supporting constant_tsc and
230// nonstop_tsc(check flags in /proc/cpuinfo)
231extern int64_t invariant_cpu_freq;
232} // namespace detail
233
234// ---------------------------------------------------------------
235// Get cpu-wide (wall-) time.
236// Cost ~9ns on Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
237// ---------------------------------------------------------------
238// note: Inlining shortens time cost per-call for 15ns in a loop of many
239// calls to this function.
240inline int64_t cpuwide_time_ns() {
241#if !defined(BAIDU_INTERNAL)
242 // nearly impossible to get the correct invariant cpu frequency on
243 // different CPU and machines. CPU-ID rarely works and frequencies
244 // in "model name" and "cpu Mhz" are both unreliable.
245 // Since clock_gettime() in newer glibc/kernel is much faster(~30ns)
246 // which is closer to the previous impl. of cpuwide_time(~10ns), we
247 // simply use the monotonic time to get rid of all related issues.
248 timespec now;
249 clock_gettime(CLOCK_MONOTONIC, &now);
250 return now.tv_sec * 1000000000L + now.tv_nsec;
251#else
252 int64_t cpu_freq = detail::invariant_cpu_freq;
253 if (cpu_freq > 0) {
254 const uint64_t tsc = detail::clock_cycles();
255 //Try to avoid overflow
256 const uint64_t sec = tsc / cpu_freq;
257 const uint64_t remain = tsc % cpu_freq;
258 // TODO: should be OK until CPU's frequency exceeds 16GHz.
259 return remain * 1000000000L / cpu_freq + sec * 1000000000L;
260 } else if (!cpu_freq) {
261 // Lack of necessary features, return system-wide monotonic time instead.
262 return monotonic_time_ns();
263 } else {
264 // Use a thread-unsafe method(OK to us) to initialize the freq
265 // to save a "if" test comparing to using a local static variable
266 detail::invariant_cpu_freq = detail::read_invariant_cpu_frequency();
267 return cpuwide_time_ns();
268 }
269#endif // defined(BAIDU_INTERNAL)
270}
271
272inline int64_t cpuwide_time_us() {
273 return cpuwide_time_ns() / 1000L;
274}
275
276inline int64_t cpuwide_time_ms() {
277 return cpuwide_time_ns() / 1000000L;
278}
279
280inline int64_t cpuwide_time_s() {
281 return cpuwide_time_ns() / 1000000000L;
282}
283
284// --------------------------------------------------------------------
285// Get elapse since the Epoch.
286// No gettimeofday_ns() because resolution of timeval is microseconds.
287// Cost ~40ns on 2.6.32_1-12-0-0, Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
288// --------------------------------------------------------------------
289inline int64_t gettimeofday_us() {
290 timeval now;
291 gettimeofday(&now, NULL);
292 return now.tv_sec * 1000000L + now.tv_usec;
293}
294
295inline int64_t gettimeofday_ms() {
296 return gettimeofday_us() / 1000L;
297}
298
299inline int64_t gettimeofday_s() {
300 return gettimeofday_us() / 1000000L;
301}
302
303// ----------------------------------------
304// Control frequency of operations.
305// ----------------------------------------
306// Example:
307// EveryManyUS every_1s(1000000L);
308// while (1) {
309// ...
310// if (every_1s) {
311// // be here at most once per second
312// }
313// }
314class EveryManyUS {
315public:
316 explicit EveryManyUS(int64_t interval_us)
317 : _last_time_us(cpuwide_time_us())
318 , _interval_us(interval_us) {}
319
320 operator bool() {
321 const int64_t now_us = cpuwide_time_us();
322 if (now_us < _last_time_us + _interval_us) {
323 return false;
324 }
325 _last_time_us = now_us;
326 return true;
327 }
328
329private:
330 int64_t _last_time_us;
331 const int64_t _interval_us;
332};
333
334// ---------------
335// Count elapses
336// ---------------
337class Timer {
338public:
339
340 enum TimerType {
341 STARTED,
342 };
343
344 Timer() : _stop(0), _start(0) {}
345 explicit Timer(const TimerType) {
346 start();
347 }
348
349 // Start this timer
350 void start() {
351 _start = cpuwide_time_ns();
352 _stop = _start;
353 }
354
355 // Stop this timer
356 void stop() {
357 _stop = cpuwide_time_ns();
358 }
359
360 // Get the elapse from start() to stop(), in various units.
361 int64_t n_elapsed() const { return _stop - _start; }
362 int64_t u_elapsed() const { return n_elapsed() / 1000L; }
363 int64_t m_elapsed() const { return u_elapsed() / 1000L; }
364 int64_t s_elapsed() const { return m_elapsed() / 1000L; }
365
366 double n_elapsed(double) const { return (double)(_stop - _start); }
367 double u_elapsed(double) const { return (double)n_elapsed() / 1000.0; }
368 double m_elapsed(double) const { return (double)u_elapsed() / 1000.0; }
369 double s_elapsed(double) const { return (double)m_elapsed() / 1000.0; }
370
371private:
372 int64_t _stop;
373 int64_t _start;
374};
375
376} // namespace butil
377
378#endif // BUTIL_BAIDU_TIME_H
379