| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 | // Copyright 2017 The Abseil Authors.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////      https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.#include "absl/base/internal/unscaledcycleclock.h"#if ABSL_USE_UNSCALED_CYCLECLOCK#if defined(_WIN32)#include <intrin.h>#endif#if defined(__powerpc__) || defined(__ppc__)#ifdef __GLIBC__#include <sys/platform/ppc.h>#elif defined(__FreeBSD__)#include <sys/sysctl.h>#include <sys/types.h>#endif#endif#include "absl/base/internal/sysinfo.h"namespace absl {ABSL_NAMESPACE_BEGINnamespace base_internal {#if defined(__i386__)int64_t UnscaledCycleClock::Now() {  int64_t ret;  __asm__ volatile("rdtsc" : "=A"(ret));  return ret;}double UnscaledCycleClock::Frequency() {  return base_internal::NominalCPUFrequency();}#elif defined(__x86_64__)int64_t UnscaledCycleClock::Now() {  uint64_t low, high;  __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));  return (high << 32) | low;}double UnscaledCycleClock::Frequency() {  return base_internal::NominalCPUFrequency();}#elif defined(__powerpc__) || defined(__ppc__)int64_t UnscaledCycleClock::Now() {#ifdef __GLIBC__  return __ppc_get_timebase();#else#ifdef __powerpc64__  int64_t tbr;  asm volatile("mfspr %0, 268" : "=r"(tbr));  return tbr;#else  int32_t tbu, tbl, tmp;  asm volatile(      "0:\n"      "mftbu %[hi32]\n"      "mftb %[lo32]\n"      "mftbu %[tmp]\n"      "cmpw %[tmp],%[hi32]\n"      "bne 0b\n"      : [ hi32 ] "=r"(tbu), [ lo32 ] "=r"(tbl), [ tmp ] "=r"(tmp));  return (static_cast<int64_t>(tbu) << 32) | tbl;#endif#endif}double UnscaledCycleClock::Frequency() {#ifdef __GLIBC__  return __ppc_get_timebase_freq();#elif defined(__FreeBSD__)  static once_flag init_timebase_frequency_once;  static double timebase_frequency = 0.0;  base_internal::LowLevelCallOnce(&init_timebase_frequency_once, [&]() {    size_t length = sizeof(timebase_frequency);    sysctlbyname("kern.timecounter.tc.timebase.frequency", &timebase_frequency,                 &length, nullptr, 0);  });  return timebase_frequency;#else#error Must implement UnscaledCycleClock::Frequency()#endif}#elif defined(__aarch64__)// System timer of ARMv8 runs at a different frequency than the CPU's.// The frequency is fixed, typically in the range 1-50MHz.  It can be// read at CNTFRQ special register.  We assume the OS has set up// the virtual timer properly.int64_t UnscaledCycleClock::Now() {  int64_t virtual_timer_value;  asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));  return virtual_timer_value;}double UnscaledCycleClock::Frequency() {  uint64_t aarch64_timer_frequency;  asm volatile("mrs %0, cntfrq_el0" : "=r"(aarch64_timer_frequency));  return aarch64_timer_frequency;}#elif defined(_M_IX86) || defined(_M_X64)#pragma intrinsic(__rdtsc)int64_t UnscaledCycleClock::Now() {  return __rdtsc();}double UnscaledCycleClock::Frequency() {  return base_internal::NominalCPUFrequency();}#endif}  // namespace base_internalABSL_NAMESPACE_END}  // namespace absl#endif  // ABSL_USE_UNSCALED_CYCLECLOCK
 |