|
||||
Warning, file /include/absl/profiling/internal/periodic_sampler.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 // Copyright 2019 The Abseil Authors. 0002 // 0003 // Licensed under the Apache License, Version 2.0 (the "License"); 0004 // you may not use this file except in compliance with the License. 0005 // You may obtain a copy of the License at 0006 // 0007 // https://www.apache.org/licenses/LICENSE-2.0 0008 // 0009 // Unless required by applicable law or agreed to in writing, software 0010 // distributed under the License is distributed on an "AS IS" BASIS, 0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0012 // See the License for the specific language governing permissions and 0013 // limitations under the License. 0014 0015 #ifndef ABSL_PROFILING_INTERNAL_PERIODIC_SAMPLER_H_ 0016 #define ABSL_PROFILING_INTERNAL_PERIODIC_SAMPLER_H_ 0017 0018 #include <stdint.h> 0019 0020 #include <atomic> 0021 0022 #include "absl/base/optimization.h" 0023 #include "absl/profiling/internal/exponential_biased.h" 0024 0025 namespace absl { 0026 ABSL_NAMESPACE_BEGIN 0027 namespace profiling_internal { 0028 0029 // PeriodicSamplerBase provides the basic period sampler implementation. 0030 // 0031 // This is the base class for the templated PeriodicSampler class, which holds 0032 // a global std::atomic value identified by a user defined tag, such that 0033 // each specific PeriodSampler implementation holds its own global period. 0034 // 0035 // PeriodicSamplerBase is thread-compatible except where stated otherwise. 0036 class PeriodicSamplerBase { 0037 public: 0038 // PeriodicSamplerBase is trivial / copyable / movable / destructible. 0039 PeriodicSamplerBase() = default; 0040 PeriodicSamplerBase(PeriodicSamplerBase&&) = default; 0041 PeriodicSamplerBase(const PeriodicSamplerBase&) = default; 0042 0043 // Returns true roughly once every `period` calls. This is established by a 0044 // randomly picked `stride` that is counted down on each call to `Sample`. 0045 // This stride is picked such that the probability of `Sample()` returning 0046 // true is 1 in `period`. 0047 inline bool Sample() noexcept; 0048 0049 // The below methods are intended for optimized use cases where the 0050 // size of the inlined fast path code is highly important. Applications 0051 // should use the `Sample()` method unless they have proof that their 0052 // specific use case requires the optimizations offered by these methods. 0053 // 0054 // An example of such a use case is SwissTable sampling. All sampling checks 0055 // are in inlined SwissTable methods, and the number of call sites is huge. 0056 // In this case, the inlined code size added to each translation unit calling 0057 // SwissTable methods is non-trivial. 0058 // 0059 // The `SubtleMaybeSample()` function spuriously returns true even if the 0060 // function should not be sampled, applications MUST match each call to 0061 // 'SubtleMaybeSample()' returning true with a `SubtleConfirmSample()` call, 0062 // and use the result of the latter as the sampling decision. 0063 // In other words: the code should logically be equivalent to: 0064 // 0065 // if (SubtleMaybeSample() && SubtleConfirmSample()) { 0066 // // Sample this call 0067 // } 0068 // 0069 // In the 'inline-size' optimized case, the `SubtleConfirmSample()` call can 0070 // be placed out of line, for example, the typical use case looks as follows: 0071 // 0072 // // --- frobber.h ----------- 0073 // void FrobberSampled(); 0074 // 0075 // inline void FrobberImpl() { 0076 // // ... 0077 // } 0078 // 0079 // inline void Frobber() { 0080 // if (ABSL_PREDICT_FALSE(sampler.SubtleMaybeSample())) { 0081 // FrobberSampled(); 0082 // } else { 0083 // FrobberImpl(); 0084 // } 0085 // } 0086 // 0087 // // --- frobber.cc ----------- 0088 // void FrobberSampled() { 0089 // if (!sampler.SubtleConfirmSample())) { 0090 // // Spurious false positive 0091 // FrobberImpl(); 0092 // return; 0093 // } 0094 // 0095 // // Sampled execution 0096 // // ... 0097 // } 0098 inline bool SubtleMaybeSample() noexcept; 0099 bool SubtleConfirmSample() noexcept; 0100 0101 protected: 0102 // We explicitly don't use a virtual destructor as this class is never 0103 // virtually destroyed, and it keeps the class trivial, which avoids TLS 0104 // prologue and epilogue code for our TLS instances. 0105 ~PeriodicSamplerBase() = default; 0106 0107 // Returns the next stride for our sampler. 0108 // This function is virtual for testing purposes only. 0109 virtual int64_t GetExponentialBiased(int period) noexcept; 0110 0111 private: 0112 // Returns the current period of this sampler. Thread-safe. 0113 virtual int period() const noexcept = 0; 0114 0115 // Keep and decrement stride_ as an unsigned integer, but compare the value 0116 // to zero casted as a signed int. clang and msvc do not create optimum code 0117 // if we use signed for the combined decrement and sign comparison. 0118 // 0119 // Below 3 alternative options, all compiles generate the best code 0120 // using the unsigned increment <---> signed int comparison option. 0121 // 0122 // Option 1: 0123 // int64_t stride_; 0124 // if (ABSL_PREDICT_TRUE(++stride_ < 0)) { ... } 0125 // 0126 // GCC x64 (OK) : https://gcc.godbolt.org/z/R5MzzA 0127 // GCC ppc (OK) : https://gcc.godbolt.org/z/z7NZAt 0128 // Clang x64 (BAD): https://gcc.godbolt.org/z/t4gPsd 0129 // ICC x64 (OK) : https://gcc.godbolt.org/z/rE6s8W 0130 // MSVC x64 (OK) : https://gcc.godbolt.org/z/ARMXqS 0131 // 0132 // Option 2: 0133 // int64_t stride_ = 0; 0134 // if (ABSL_PREDICT_TRUE(--stride_ >= 0)) { ... } 0135 // 0136 // GCC x64 (OK) : https://gcc.godbolt.org/z/jSQxYK 0137 // GCC ppc (OK) : https://gcc.godbolt.org/z/VJdYaA 0138 // Clang x64 (BAD): https://gcc.godbolt.org/z/Xm4NjX 0139 // ICC x64 (OK) : https://gcc.godbolt.org/z/4snaFd 0140 // MSVC x64 (BAD): https://gcc.godbolt.org/z/BgnEKE 0141 // 0142 // Option 3: 0143 // uint64_t stride_; 0144 // if (ABSL_PREDICT_TRUE(static_cast<int64_t>(++stride_) < 0)) { ... } 0145 // 0146 // GCC x64 (OK) : https://gcc.godbolt.org/z/bFbfPy 0147 // GCC ppc (OK) : https://gcc.godbolt.org/z/S9KkUE 0148 // Clang x64 (OK) : https://gcc.godbolt.org/z/UYzRb4 0149 // ICC x64 (OK) : https://gcc.godbolt.org/z/ptTNfD 0150 // MSVC x64 (OK) : https://gcc.godbolt.org/z/76j4-5 0151 uint64_t stride_ = 0; 0152 absl::profiling_internal::ExponentialBiased rng_; 0153 }; 0154 0155 inline bool PeriodicSamplerBase::SubtleMaybeSample() noexcept { 0156 // See comments on `stride_` for the unsigned increment / signed compare. 0157 if (ABSL_PREDICT_TRUE(static_cast<int64_t>(++stride_) < 0)) { 0158 return false; 0159 } 0160 return true; 0161 } 0162 0163 inline bool PeriodicSamplerBase::Sample() noexcept { 0164 return ABSL_PREDICT_FALSE(SubtleMaybeSample()) ? SubtleConfirmSample() 0165 : false; 0166 } 0167 0168 // PeriodicSampler is a concreted periodic sampler implementation. 0169 // The user provided Tag identifies the implementation, and is required to 0170 // isolate the global state of this instance from other instances. 0171 // 0172 // Typical use case: 0173 // 0174 // struct HashTablezTag {}; 0175 // thread_local PeriodicSampler<HashTablezTag, 100> sampler; 0176 // 0177 // void HashTableSamplingLogic(...) { 0178 // if (sampler.Sample()) { 0179 // HashTableSlowSamplePath(...); 0180 // } 0181 // } 0182 // 0183 template <typename Tag, int default_period = 0> 0184 class PeriodicSampler final : public PeriodicSamplerBase { 0185 public: 0186 ~PeriodicSampler() = default; 0187 0188 int period() const noexcept final { 0189 return period_.load(std::memory_order_relaxed); 0190 } 0191 0192 // Sets the global period for this sampler. Thread-safe. 0193 // Setting a period of 0 disables the sampler, i.e., every call to Sample() 0194 // will return false. Setting a period of 1 puts the sampler in 'always on' 0195 // mode, i.e., every call to Sample() returns true. 0196 static void SetGlobalPeriod(int period) { 0197 period_.store(period, std::memory_order_relaxed); 0198 } 0199 0200 private: 0201 static std::atomic<int> period_; 0202 }; 0203 0204 template <typename Tag, int default_period> 0205 std::atomic<int> PeriodicSampler<Tag, default_period>::period_(default_period); 0206 0207 } // namespace profiling_internal 0208 ABSL_NAMESPACE_END 0209 } // namespace absl 0210 0211 #endif // ABSL_PROFILING_INTERNAL_PERIODIC_SAMPLER_H_
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |