diff --git a/src/butil/time.cpp b/src/butil/time.cpp index 2c726d9b52..e929997ad6 100644 --- a/src/butil/time.cpp +++ b/src/butil/time.cpp @@ -143,16 +143,22 @@ int64_t read_cpu_frequency(bool* invariant_tsc) { } // Return value must be >= 0 -int64_t read_invariant_cpu_frequency() { +static int64_t read_invariant_cpu_frequency() { bool invariant_tsc = false; - const int64_t freq = read_cpu_frequency(&invariant_tsc); + int64_t freq = -1; +#if defined(__aarch64__) && defined(BUTIL_USE_CPU_FREQUENCY) + __asm__ __volatile__("mrs %0, CNTFRQ_EL0" : "=r"(freq)); +#else + freq = read_cpu_frequency(&invariant_tsc); if (!invariant_tsc || freq < 0) { return 0; } +#endif + return freq; } -int64_t invariant_cpu_freq = -1; +int64_t invariant_cpu_freq = read_invariant_cpu_frequency(); } // namespace detail } // namespace butil diff --git a/src/butil/time.h b/src/butil/time.h index c57000ea99..71156b3f13 100644 --- a/src/butil/time.h +++ b/src/butil/time.h @@ -265,10 +265,12 @@ inline uint64_t clock_cycles() { #error "unsupported arch" #endif } -extern int64_t read_invariant_cpu_frequency(); + // Be positive iff: // 1 Intel x86_64 CPU (multiple cores) supporting constant_tsc and // nonstop_tsc(check flags in /proc/cpuinfo) +// 2 aarch64, where the counter frequency is read from CNTFRQ_EL0. +// Only computed when BUTIL_USE_CPU_FREQUENCY is defined. extern int64_t invariant_cpu_freq; } // namespace detail @@ -279,7 +281,7 @@ extern int64_t invariant_cpu_freq; // note: Inlining shortens time cost per-call for 15ns in a loop of many // calls to this function. inline int64_t cpuwide_time_ns() { -#if !defined(BAIDU_INTERNAL) +#if !defined(BAIDU_INTERNAL) && !defined(BUTIL_USE_CPU_FREQUENCY) // nearly impossible to get the correct invariant cpu frequency on // different CPU and machines. CPU-ID rarely works and frequencies // in "model name" and "cpu Mhz" are both unreliable. @@ -298,16 +300,11 @@ inline int64_t cpuwide_time_ns() { const uint64_t remain = tsc % cpu_freq; // TODO: should be OK until CPU's frequency exceeds 16GHz. return remain * 1000000000L / cpu_freq + sec * 1000000000L; - } else if (!cpu_freq) { + } else { // Lack of necessary features, return system-wide monotonic time instead. return monotonic_time_ns(); - } else { - // Use a thread-unsafe method(OK to us) to initialize the freq - // to save a "if" test comparing to using a local static variable - detail::invariant_cpu_freq = detail::read_invariant_cpu_frequency(); - return cpuwide_time_ns(); } -#endif // defined(BAIDU_INTERNAL) +#endif // defined(BAIDU_INTERNAL) || defined(BUTIL_USE_CPU_FREQUENCY) } // Get cpu clock time of the current thread in nanoseconds without the time spent in blocking I/O operations.