unscaledcycleclock.h (3569B)
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 // UnscaledCycleClock 16 // An UnscaledCycleClock yields the value and frequency of a cycle counter 17 // that increments at a rate that is approximately constant. 18 // This class is for internal use only, you should consider using CycleClock 19 // instead. 20 // 21 // Notes: 22 // The cycle counter frequency is not necessarily the core clock frequency. 23 // That is, CycleCounter cycles are not necessarily "CPU cycles". 24 // 25 // An arbitrary offset may have been added to the counter at power on. 26 // 27 // On some platforms, the rate and offset of the counter may differ 28 // slightly when read from different CPUs of a multiprocessor. Usually, 29 // we try to ensure that the operating system adjusts values periodically 30 // so that values agree approximately. If you need stronger guarantees, 31 // consider using alternate interfaces. 32 // 33 // The CPU is not required to maintain the ordering of a cycle counter read 34 // with respect to surrounding instructions. 35 36 #ifndef ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_ 37 #define ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_ 38 39 #include <cstdint> 40 41 #if defined(__APPLE__) 42 #include <TargetConditionals.h> 43 #endif 44 45 #include "absl/base/config.h" 46 #include "absl/base/internal/unscaledcycleclock_config.h" 47 48 #if ABSL_USE_UNSCALED_CYCLECLOCK 49 50 namespace absl { 51 ABSL_NAMESPACE_BEGIN 52 namespace time_internal { 53 class UnscaledCycleClockWrapperForGetCurrentTime; 54 } // namespace time_internal 55 56 namespace base_internal { 57 class CycleClock; 58 class UnscaledCycleClockWrapperForInitializeFrequency; 59 60 class UnscaledCycleClock { 61 private: 62 UnscaledCycleClock() = delete; 63 64 // Return the value of a cycle counter that counts at a rate that is 65 // approximately constant. 66 static int64_t Now(); 67 68 // Return the how much UnscaledCycleClock::Now() increases per second. 69 // This is not necessarily the core CPU clock frequency. 70 // It may be the nominal value report by the kernel, rather than a measured 71 // value. 72 static double Frequency(); 73 74 // Allowed users 75 friend class base_internal::CycleClock; 76 friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime; 77 friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency; 78 }; 79 80 #if defined(__x86_64__) 81 82 inline int64_t UnscaledCycleClock::Now() { 83 uint64_t low, high; 84 __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); 85 return static_cast<int64_t>((high << 32) | low); 86 } 87 88 #elif defined(__aarch64__) 89 90 // System timer of ARMv8 runs at a different frequency than the CPU's. 91 // The frequency is fixed, typically in the range 1-50MHz. It can be 92 // read at CNTFRQ special register. We assume the OS has set up 93 // the virtual timer properly. 94 inline int64_t UnscaledCycleClock::Now() { 95 int64_t virtual_timer_value; 96 asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value)); 97 return virtual_timer_value; 98 } 99 100 #endif 101 102 } // namespace base_internal 103 ABSL_NAMESPACE_END 104 } // namespace absl 105 106 #endif // ABSL_USE_UNSCALED_CYCLECLOCK 107 108 #endif // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_