unscaledcycleclock.cc (3275B)
1 // Copyright 2017 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "absl/base/internal/unscaledcycleclock.h" 16 17 #if ABSL_USE_UNSCALED_CYCLECLOCK 18 19 #if defined(_WIN32) 20 #include <intrin.h> 21 #endif 22 23 #if defined(__powerpc__) || defined(__ppc__) 24 #ifdef __GLIBC__ 25 #include <sys/platform/ppc.h> 26 #elif defined(__FreeBSD__) 27 // clang-format off 28 // This order does actually matter =(. 29 #include <sys/types.h> 30 #include <sys/sysctl.h> 31 // clang-format on 32 33 #include "absl/base/call_once.h" 34 #endif 35 #endif 36 37 #include "absl/base/internal/sysinfo.h" 38 39 namespace absl { 40 ABSL_NAMESPACE_BEGIN 41 namespace base_internal { 42 43 #if defined(__i386__) 44 45 int64_t UnscaledCycleClock::Now() { 46 int64_t ret; 47 __asm__ volatile("rdtsc" : "=A"(ret)); 48 return ret; 49 } 50 51 double UnscaledCycleClock::Frequency() { 52 return base_internal::NominalCPUFrequency(); 53 } 54 55 #elif defined(__x86_64__) 56 57 double UnscaledCycleClock::Frequency() { 58 return base_internal::NominalCPUFrequency(); 59 } 60 61 #elif defined(__powerpc__) || defined(__ppc__) 62 63 int64_t UnscaledCycleClock::Now() { 64 #ifdef __GLIBC__ 65 return __ppc_get_timebase(); 66 #else 67 #ifdef __powerpc64__ 68 int64_t tbr; 69 asm volatile("mfspr %0, 268" : "=r"(tbr)); 70 return tbr; 71 #else 72 int32_t tbu, tbl, tmp; 73 asm volatile( 74 "mftbu %[hi32]\n" 75 "mftb %[lo32]\n" 76 "mftbu %[tmp]\n" 77 "cmpw %[tmp],%[hi32]\n" 78 "bne $-16\n" // Retry on failure. 79 : [hi32] "=r"(tbu), [lo32] "=r"(tbl), [tmp] "=r"(tmp)); 80 return (static_cast<int64_t>(tbu) << 32) | tbl; 81 #endif 82 #endif 83 } 84 85 double UnscaledCycleClock::Frequency() { 86 #ifdef __GLIBC__ 87 return __ppc_get_timebase_freq(); 88 #elif defined(_AIX) 89 // This is the same constant value as returned by 90 // __ppc_get_timebase_freq(). 91 return static_cast<double>(512000000); 92 #elif defined(__FreeBSD__) 93 static once_flag init_timebase_frequency_once; 94 static double timebase_frequency = 0.0; 95 base_internal::LowLevelCallOnce(&init_timebase_frequency_once, [&]() { 96 size_t length = sizeof(timebase_frequency); 97 sysctlbyname("kern.timecounter.tc.timebase.frequency", &timebase_frequency, 98 &length, nullptr, 0); 99 }); 100 return timebase_frequency; 101 #else 102 #error Must implement UnscaledCycleClock::Frequency() 103 #endif 104 } 105 106 #elif defined(__aarch64__) 107 108 double UnscaledCycleClock::Frequency() { 109 uint64_t aarch64_timer_frequency; 110 asm volatile("mrs %0, cntfrq_el0" : "=r"(aarch64_timer_frequency)); 111 return aarch64_timer_frequency; 112 } 113 114 #elif defined(_M_IX86) || defined(_M_X64) 115 116 #pragma intrinsic(__rdtsc) 117 118 int64_t UnscaledCycleClock::Now() { return __rdtsc(); } 119 120 double UnscaledCycleClock::Frequency() { 121 return base_internal::NominalCPUFrequency(); 122 } 123 124 #endif 125 126 } // namespace base_internal 127 ABSL_NAMESPACE_END 128 } // namespace absl 129 130 #endif // ABSL_USE_UNSCALED_CYCLECLOCK