cordz_functions.cc (3227B)
1 // Copyright 2019 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/strings/internal/cordz_functions.h" 16 17 #include <atomic> 18 #include <cmath> 19 #include <limits> 20 #include <random> 21 22 #include "absl/base/attributes.h" 23 #include "absl/base/config.h" 24 #include "absl/base/internal/raw_logging.h" 25 #include "absl/profiling/internal/exponential_biased.h" 26 27 namespace absl { 28 ABSL_NAMESPACE_BEGIN 29 namespace cord_internal { 30 namespace { 31 32 // The average interval until the next sample. A value of 0 disables profiling 33 // while a value of 1 will profile all Cords. 34 std::atomic<int> g_cordz_mean_interval(50000); 35 36 } // namespace 37 38 #ifdef ABSL_INTERNAL_CORDZ_ENABLED 39 40 // Special negative 'not initialized' per thread value for cordz_next_sample. 41 static constexpr int64_t kInitCordzNextSample = -1; 42 43 ABSL_CONST_INIT thread_local SamplingState cordz_next_sample = { 44 kInitCordzNextSample, 1}; 45 46 // kIntervalIfDisabled is the number of profile-eligible events need to occur 47 // before the code will confirm that cordz is still disabled. 48 constexpr int64_t kIntervalIfDisabled = 1 << 16; 49 50 ABSL_ATTRIBUTE_NOINLINE int64_t 51 cordz_should_profile_slow(SamplingState& state) { 52 53 thread_local absl::profiling_internal::ExponentialBiased 54 exponential_biased_generator; 55 int32_t mean_interval = get_cordz_mean_interval(); 56 57 // Check if we disabled profiling. If so, set the next sample to a "large" 58 // number to minimize the overhead of the should_profile codepath. 59 if (mean_interval <= 0) { 60 state = {kIntervalIfDisabled, kIntervalIfDisabled}; 61 return 0; 62 } 63 64 // Check if we're always sampling. 65 if (mean_interval == 1) { 66 state = {1, 1}; 67 return 1; 68 } 69 70 if (cordz_next_sample.next_sample <= 0) { 71 // If first check on current thread, check cordz_should_profile() 72 // again using the created (initial) stride in cordz_next_sample. 73 const bool initialized = 74 cordz_next_sample.next_sample != kInitCordzNextSample; 75 auto old_stride = state.sample_stride; 76 auto stride = exponential_biased_generator.GetStride(mean_interval); 77 state = {stride, stride}; 78 bool should_sample = initialized || cordz_should_profile() > 0; 79 return should_sample ? old_stride : 0; 80 } 81 82 --state.next_sample; 83 return 0; 84 } 85 86 void cordz_set_next_sample_for_testing(int64_t next_sample) { 87 cordz_next_sample = {next_sample, next_sample}; 88 } 89 90 #endif // ABSL_INTERNAL_CORDZ_ENABLED 91 92 int32_t get_cordz_mean_interval() { 93 return g_cordz_mean_interval.load(std::memory_order_acquire); 94 } 95 96 void set_cordz_mean_interval(int32_t mean_interval) { 97 g_cordz_mean_interval.store(mean_interval, std::memory_order_release); 98 } 99 100 } // namespace cord_internal 101 ABSL_NAMESPACE_END 102 } // namespace absl