Coverage Report

Created: 2025-09-17 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/brpc/src/butil/time.h
Line
Count
Source
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
34
typedef int clockid_t;
35
36
// clock_gettime is not available in MacOS < 10.12
37
int clock_gettime(clockid_t id, timespec* time);
38
39
#endif
40
41
namespace butil {
42
43
// Get SVN revision of this copy.
44
const 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.
51
0
inline void timespec_normalize(timespec* tm) {
52
0
    if (tm->tv_nsec >= 1000000000L) {
53
0
        const int64_t added_sec = tm->tv_nsec / 1000000000L;
54
0
        tm->tv_sec += added_sec;
55
0
        tm->tv_nsec -= added_sec * 1000000000L;
56
0
    } else if (tm->tv_nsec < 0) {
57
0
        const int64_t sub_sec = (tm->tv_nsec - 999999999L) / 1000000000L;
58
0
        tm->tv_sec += sub_sec;
59
0
        tm->tv_nsec -= sub_sec * 1000000000L;
60
0
    }
61
0
}
62
63
// Add timespec |span| into timespec |*tm|.
64
0
inline void timespec_add(timespec *tm, const timespec& span) {
65
0
    tm->tv_sec += span.tv_sec;
66
0
    tm->tv_nsec += span.tv_nsec;
67
0
    timespec_normalize(tm);
68
0
}
69
70
// Minus timespec |span| from timespec |*tm|. 
71
// tm->tv_nsec will be inside [0, 1,000,000,000)
72
0
inline void timespec_minus(timespec *tm, const timespec& span) {
73
0
    tm->tv_sec -= span.tv_sec;
74
0
    tm->tv_nsec -= span.tv_nsec;
75
0
    timespec_normalize(tm);
76
0
}
77
78
// ------------------------------------------------------------------
79
// Get the timespec after specified duration from |start_time|
80
// ------------------------------------------------------------------
81
0
inline timespec nanoseconds_from(timespec start_time, int64_t nanoseconds) {
82
0
    start_time.tv_nsec += nanoseconds;
83
0
    timespec_normalize(&start_time);
84
0
    return start_time;
85
0
}
86
87
0
inline timespec microseconds_from(timespec start_time, int64_t microseconds) {
88
0
    return nanoseconds_from(start_time, microseconds * 1000L);
89
0
}
90
91
0
inline timespec milliseconds_from(timespec start_time, int64_t milliseconds) {
92
0
    return nanoseconds_from(start_time, milliseconds * 1000000L);
93
0
}
94
95
0
inline timespec seconds_from(timespec start_time, int64_t seconds) {
96
0
    return nanoseconds_from(start_time, seconds * 1000000000L);
97
0
}
98
99
// --------------------------------------------------------------------
100
// Get the timespec after specified duration from now (CLOCK_REALTIME)
101
// --------------------------------------------------------------------
102
0
inline timespec nanoseconds_from_now(int64_t nanoseconds) {
103
0
    timespec time;
104
0
    clock_gettime(CLOCK_REALTIME, &time);
105
0
    return nanoseconds_from(time, nanoseconds);
106
0
}
107
108
0
inline timespec microseconds_from_now(int64_t microseconds) {
109
0
    return nanoseconds_from_now(microseconds * 1000L);
110
0
}
111
112
0
inline timespec milliseconds_from_now(int64_t milliseconds) {
113
0
    return nanoseconds_from_now(milliseconds * 1000000L);
114
0
}
115
116
0
inline timespec seconds_from_now(int64_t seconds) {
117
0
    return nanoseconds_from_now(seconds * 1000000000L);
118
0
}
119
120
0
inline timespec timespec_from_now(const timespec& span) {
121
0
    timespec time;
122
0
    clock_gettime(CLOCK_REALTIME, &time);
123
0
    timespec_add(&time, span);
124
0
    return time;
125
0
}
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
132
0
inline int64_t timespec_to_nanoseconds(const timespec& ts) {
133
0
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
134
0
}
135
136
0
inline int64_t timespec_to_microseconds(const timespec& ts) {
137
0
    return timespec_to_nanoseconds(ts) / 1000L;
138
0
}
139
140
0
inline int64_t timespec_to_milliseconds(const timespec& ts) {
141
0
    return timespec_to_nanoseconds(ts) / 1000000L;
142
0
}
143
144
0
inline int64_t timespec_to_seconds(const timespec& ts) {
145
0
    return timespec_to_nanoseconds(ts) / 1000000000L;
146
0
}
147
148
0
inline timespec nanoseconds_to_timespec(int64_t ns) {
149
0
    timespec ts;
150
0
    ts.tv_sec = ns / 1000000000L;
151
0
    ts.tv_nsec = ns - ts.tv_sec * 1000000000L;
152
0
    return ts;
153
0
}
154
155
0
inline timespec microseconds_to_timespec(int64_t us) {
156
0
    return nanoseconds_to_timespec(us * 1000L);
157
0
}
158
159
0
inline timespec milliseconds_to_timespec(int64_t ms) {
160
0
    return nanoseconds_to_timespec(ms * 1000000L);
161
0
}
162
163
0
inline timespec seconds_to_timespec(int64_t s) {
164
0
    return nanoseconds_to_timespec(s * 1000000000L);
165
0
}
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
// ---------------------------------------------------------------------
172
0
inline int64_t timeval_to_microseconds(const timeval& tv) {
173
0
    return tv.tv_sec * 1000000L + tv.tv_usec;
174
0
}
175
176
0
inline int64_t timeval_to_milliseconds(const timeval& tv) {
177
0
    return timeval_to_microseconds(tv) / 1000L;
178
0
}
179
180
0
inline int64_t timeval_to_seconds(const timeval& tv) {
181
0
    return timeval_to_microseconds(tv) / 1000000L;
182
0
}
183
184
0
inline timeval microseconds_to_timeval(int64_t us) {
185
0
    timeval tv;
186
0
    tv.tv_sec = us / 1000000L;
187
0
    tv.tv_usec = us - tv.tv_sec * 1000000L;
188
0
    return tv;
189
0
}
190
191
0
inline timeval milliseconds_to_timeval(int64_t ms) {
192
0
    return microseconds_to_timeval(ms * 1000L);
193
0
}
194
195
0
inline timeval seconds_to_timeval(int64_t s) {
196
0
    return microseconds_to_timeval(s * 1000000L);
197
0
}
198
199
// ---------------------------------------------------------------
200
// Get system-wide monotonic time.
201
// ---------------------------------------------------------------
202
extern int64_t monotonic_time_ns();
203
204
0
inline int64_t monotonic_time_us() { 
205
0
    return monotonic_time_ns() / 1000L; 
206
0
}
207
208
0
inline int64_t monotonic_time_ms() {
209
0
    return monotonic_time_ns() / 1000000L; 
210
0
}
211
212
0
inline int64_t monotonic_time_s() {
213
0
    return monotonic_time_ns() / 1000000000L;
214
0
}
215
216
namespace detail {
217
0
inline uint64_t clock_cycles() {
218
0
#if defined(__x86_64__) || defined(__amd64__)
219
0
    unsigned int lo = 0;
220
0
    unsigned int hi = 0;
221
0
    // We cannot use "=A", since this would use %rax on x86_64
222
0
    __asm__ __volatile__ (
223
0
        "rdtsc"
224
0
        : "=a" (lo), "=d" (hi)
225
0
        );
226
0
    return ((uint64_t)hi << 32) | lo;
227
0
#elif defined(__aarch64__)
228
0
    uint64_t virtual_timer_value;
229
0
    asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
230
0
    return virtual_timer_value;
231
0
#elif defined(__ARM_ARCH)
232
0
  #if (__ARM_ARCH >= 6)
233
0
    unsigned int pmccntr;
234
0
    unsigned int pmuseren;
235
0
    unsigned int pmcntenset;
236
0
    // Read the user mode perf monitor counter access permissions.
237
0
    asm volatile ("mrc p15, 0, %0, c9, c14, 0" : "=r" (pmuseren));
238
0
    if (pmuseren & 1) {  // Allows reading perfmon counters for user mode code.
239
0
        asm volatile ("mrc p15, 0, %0, c9, c12, 1" : "=r" (pmcntenset));
240
0
        if (pmcntenset & 0x80000000ul) {  // Is it counting?
241
0
            asm volatile ("mrc p15, 0, %0, c9, c13, 0" : "=r" (pmccntr));
242
0
            // The counter is set up to count every 64th cycle
243
0
            return static_cast<uint64_t>(pmccntr) * 64;  // Should optimize to << 6
244
0
        }
245
0
    }
246
0
  #else
247
0
    #error "unsupported arm_arch"
248
0
  #endif
249
0
#elif defined(__loongarch64)
250
0
    uint64_t stable_counter;
251
0
    uint64_t counter_id;
252
0
    __asm__ __volatile__ (
253
0
        "rdtime.d %1, %0"
254
0
        : "=r" (stable_counter), "=r" (counter_id)
255
0
        );
256
0
    return stable_counter;
257
0
#else
258
0
  #error "unsupported arch"
259
0
#endif
260
0
}
261
extern int64_t read_invariant_cpu_frequency();
262
// Be positive iff:
263
// 1 Intel x86_64 CPU (multiple cores) supporting constant_tsc and
264
// nonstop_tsc(check flags in /proc/cpuinfo)
265
extern int64_t invariant_cpu_freq;
266
}  // namespace detail
267
268
// ---------------------------------------------------------------
269
// Get cpu-wide (wall-) time.
270
// Cost ~9ns on Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
271
// ---------------------------------------------------------------
272
// note: Inlining shortens time cost per-call for 15ns in a loop of many
273
//       calls to this function.
274
0
inline int64_t cpuwide_time_ns() {
275
0
#if !defined(BAIDU_INTERNAL)
276
    // nearly impossible to get the correct invariant cpu frequency on
277
    // different CPU and machines. CPU-ID rarely works and frequencies
278
    // in "model name" and "cpu Mhz" are both unreliable.
279
    // Since clock_gettime() in newer glibc/kernel is much faster(~30ns)
280
    // which is closer to the previous impl. of cpuwide_time(~10ns), we
281
    // simply use the monotonic time to get rid of all related issues.
282
0
    timespec now;
283
0
    clock_gettime(CLOCK_MONOTONIC, &now);
284
0
    return now.tv_sec * 1000000000L + now.tv_nsec;
285
#else
286
    int64_t cpu_freq = detail::invariant_cpu_freq;
287
    if (cpu_freq > 0) {
288
        const uint64_t tsc = detail::clock_cycles();
289
        //Try to avoid overflow
290
        const uint64_t sec = tsc / cpu_freq;
291
        const uint64_t remain = tsc % cpu_freq;
292
        // TODO: should be OK until CPU's frequency exceeds 16GHz.
293
        return remain * 1000000000L / cpu_freq + sec * 1000000000L;
294
    } else if (!cpu_freq) {
295
        // Lack of necessary features, return system-wide monotonic time instead.
296
        return monotonic_time_ns();
297
    } else {
298
        // Use a thread-unsafe method(OK to us) to initialize the freq
299
        // to save a "if" test comparing to using a local static variable
300
        detail::invariant_cpu_freq = detail::read_invariant_cpu_frequency();
301
        return cpuwide_time_ns();
302
    }
303
#endif // defined(BAIDU_INTERNAL)
304
0
}
305
306
// Get cpu clock time of the current thread in nanoseconds without the time spent in blocking I/O operations.
307
// Cost ~200ns
308
0
inline int64_t cputhread_time_ns() {
309
0
    timespec now;
310
0
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
311
0
    return now.tv_sec * 1000000000L + now.tv_nsec;
312
0
}
313
314
0
inline int64_t cpuwide_time_us() {
315
0
    return cpuwide_time_ns() / 1000L;
316
0
}
317
318
0
inline int64_t cpuwide_time_ms() { 
319
0
    return cpuwide_time_ns() / 1000000L;
320
0
}
321
322
0
inline int64_t cpuwide_time_s() {
323
0
    return cpuwide_time_ns() / 1000000000L;
324
0
}
325
326
// --------------------------------------------------------------------
327
// Get elapse since the Epoch.                                          
328
// No gettimeofday_ns() because resolution of timeval is microseconds.  
329
// Cost ~40ns on 2.6.32_1-12-0-0, Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
330
// --------------------------------------------------------------------
331
13
inline int64_t gettimeofday_us() {
332
13
    timeval now;
333
13
    gettimeofday(&now, NULL);
334
13
    return now.tv_sec * 1000000L + now.tv_usec;
335
13
}
336
337
0
inline int64_t gettimeofday_ms() {
338
0
    return gettimeofday_us() / 1000L;
339
0
}
340
341
0
inline int64_t gettimeofday_s() {
342
0
    return gettimeofday_us() / 1000000L;
343
0
}
344
345
// ----------------------------------------
346
// Control frequency of operations.
347
// ----------------------------------------
348
// Example:
349
//   EveryManyUS every_1s(1000000L);
350
//   while (1) {
351
//       ...
352
//       if (every_1s) {
353
//           // be here at most once per second
354
//       }
355
//   }
356
class EveryManyUS {
357
public:
358
    explicit EveryManyUS(int64_t interval_us)
359
        : _last_time_us(cpuwide_time_us())
360
0
        , _interval_us(interval_us) {}
361
    
362
0
    operator bool() {
363
0
        const int64_t now_us = cpuwide_time_us();
364
0
        if (now_us < _last_time_us + _interval_us) {
365
0
            return false;
366
0
        }
367
0
        _last_time_us = now_us;
368
0
        return true;
369
0
    }
370
371
private:
372
    int64_t _last_time_us;
373
    const int64_t _interval_us;
374
};
375
376
// ---------------
377
//  Count elapses
378
// ---------------
379
class Timer {
380
public:
381
382
    enum TimerType {
383
        STARTED,
384
    };
385
386
0
    Timer() : _stop(0), _start(0) {}
387
0
    explicit Timer(const TimerType) : Timer() {
388
0
        start();
389
0
    }
390
391
    // Start this timer
392
0
    void start() {
393
0
        _start = cpuwide_time_ns();
394
0
        _stop = _start;
395
0
    }
396
    
397
    // Stop this timer
398
0
    void stop() {
399
0
        _stop = cpuwide_time_ns();
400
0
    }
401
402
    // Get the elapse from start() to stop(), in various units.
403
0
    int64_t n_elapsed() const { return _stop - _start; }
404
0
    int64_t u_elapsed() const { return n_elapsed() / 1000L; }
405
0
    int64_t m_elapsed() const { return u_elapsed() / 1000L; }
406
0
    int64_t s_elapsed() const { return m_elapsed() / 1000L; }
407
408
0
    double n_elapsed(double) const { return (double)(_stop - _start); }
409
0
    double u_elapsed(double) const { return (double)n_elapsed() / 1000.0; }
410
0
    double m_elapsed(double) const { return (double)u_elapsed() / 1000.0; }
411
0
    double s_elapsed(double) const { return (double)m_elapsed() / 1000.0; }
412
    
413
private:
414
    int64_t _stop;
415
    int64_t _start;
416
};
417
418
}  // namespace butil
419
420
#endif  // BUTIL_BAIDU_TIME_H