cycleclock.h (4983B)
1 // 2 // Copyright 2017 The Abseil Authors. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // https://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 // ----------------------------------------------------------------------------- 18 // File: cycleclock.h 19 // ----------------------------------------------------------------------------- 20 // 21 // This header file defines a `CycleClock`, which yields the value and frequency 22 // of a cycle counter that increments at a rate that is approximately constant. 23 // 24 // NOTE: 25 // 26 // The cycle counter frequency is not necessarily related to the core clock 27 // frequency and should not be treated as such. That is, `CycleClock` cycles are 28 // not necessarily "CPU cycles" and code should not rely on that behavior, even 29 // if experimentally observed. 30 // 31 // An arbitrary offset may have been added to the counter at power on. 32 // 33 // On some platforms, the rate and offset of the counter may differ 34 // slightly when read from different CPUs of a multiprocessor. Usually, 35 // we try to ensure that the operating system adjusts values periodically 36 // so that values agree approximately. If you need stronger guarantees, 37 // consider using alternate interfaces. 38 // 39 // The CPU is not required to maintain the ordering of a cycle counter read 40 // with respect to surrounding instructions. 41 42 #ifndef ABSL_BASE_INTERNAL_CYCLECLOCK_H_ 43 #define ABSL_BASE_INTERNAL_CYCLECLOCK_H_ 44 45 #include <atomic> 46 #include <cstdint> 47 48 #include "absl/base/attributes.h" 49 #include "absl/base/config.h" 50 #include "absl/base/internal/cycleclock_config.h" 51 #include "absl/base/internal/unscaledcycleclock.h" 52 53 namespace absl { 54 ABSL_NAMESPACE_BEGIN 55 namespace base_internal { 56 57 using CycleClockSourceFunc = int64_t (*)(); 58 59 // ----------------------------------------------------------------------------- 60 // CycleClock 61 // ----------------------------------------------------------------------------- 62 class CycleClock { 63 public: 64 // CycleClock::Now() 65 // 66 // Returns the value of a cycle counter that counts at a rate that is 67 // approximately constant. 68 static int64_t Now(); 69 70 // CycleClock::Frequency() 71 // 72 // Returns the amount by which `CycleClock::Now()` increases per second. Note 73 // that this value may not necessarily match the core CPU clock frequency. 74 static double Frequency(); 75 76 private: 77 #if ABSL_USE_UNSCALED_CYCLECLOCK 78 static CycleClockSourceFunc LoadCycleClockSource(); 79 80 static constexpr int32_t kShift = kCycleClockShift; 81 static constexpr double kFrequencyScale = kCycleClockFrequencyScale; 82 83 ABSL_CONST_INIT static std::atomic<CycleClockSourceFunc> cycle_clock_source_; 84 #endif // ABSL_USE_UNSCALED_CYCLECLOC 85 86 CycleClock() = delete; // no instances 87 CycleClock(const CycleClock&) = delete; 88 CycleClock& operator=(const CycleClock&) = delete; 89 90 friend class CycleClockSource; 91 }; 92 93 class CycleClockSource { 94 private: 95 // CycleClockSource::Register() 96 // 97 // Register a function that provides an alternate source for the unscaled CPU 98 // cycle count value. The source function must be async signal safe, must not 99 // call CycleClock::Now(), and must have a frequency that matches that of the 100 // unscaled clock used by CycleClock. A nullptr value resets CycleClock to use 101 // the default source. 102 static void Register(CycleClockSourceFunc source); 103 }; 104 105 #if ABSL_USE_UNSCALED_CYCLECLOCK 106 107 inline CycleClockSourceFunc CycleClock::LoadCycleClockSource() { 108 #if !defined(__x86_64__) 109 // Optimize for the common case (no callback) by first doing a relaxed load; 110 // this is significantly faster on non-x86 platforms. 111 if (cycle_clock_source_.load(std::memory_order_relaxed) == nullptr) { 112 return nullptr; 113 } 114 #endif // !defined(__x86_64__) 115 116 // This corresponds to the store(std::memory_order_release) in 117 // CycleClockSource::Register, and makes sure that any updates made prior to 118 // registering the callback are visible to this thread before the callback 119 // is invoked. 120 return cycle_clock_source_.load(std::memory_order_acquire); 121 } 122 123 // Accessing globals in inlined code in Window DLLs is problematic. 124 #ifndef _WIN32 125 inline int64_t CycleClock::Now() { 126 auto fn = LoadCycleClockSource(); 127 if (fn == nullptr) { 128 return base_internal::UnscaledCycleClock::Now() >> kShift; 129 } 130 return fn() >> kShift; 131 } 132 #endif 133 134 inline double CycleClock::Frequency() { 135 return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency(); 136 } 137 138 #endif // ABSL_USE_UNSCALED_CYCLECLOCK 139 140 } // namespace base_internal 141 ABSL_NAMESPACE_END 142 } // namespace absl 143 144 #endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_