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/exponential_biased.h" 25 #include "absl/base/internal/raw_logging.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 int64_t cordz_next_sample = kInitCordzNextSample; 44 45 // kIntervalIfDisabled is the number of profile-eligible events need to occur 46 // before the code will confirm that cordz is still disabled. 47 constexpr int64_t kIntervalIfDisabled = 1 << 16; 48 cordz_should_profile_slow()49ABSL_ATTRIBUTE_NOINLINE bool cordz_should_profile_slow() { 50 51 thread_local absl::base_internal::ExponentialBiased 52 exponential_biased_generator; 53 int32_t mean_interval = get_cordz_mean_interval(); 54 55 // Check if we disabled profiling. If so, set the next sample to a "large" 56 // number to minimize the overhead of the should_profile codepath. 57 if (mean_interval <= 0) { 58 cordz_next_sample = kIntervalIfDisabled; 59 return false; 60 } 61 62 // Check if we're always sampling. 63 if (mean_interval == 1) { 64 cordz_next_sample = 1; 65 return true; 66 } 67 68 if (cordz_next_sample <= 0) { 69 // If first check on current thread, check cordz_should_profile() 70 // again using the created (initial) stride in cordz_next_sample. 71 const bool initialized = cordz_next_sample != kInitCordzNextSample; 72 cordz_next_sample = exponential_biased_generator.GetStride(mean_interval); 73 return initialized || cordz_should_profile(); 74 } 75 76 --cordz_next_sample; 77 return false; 78 } 79 cordz_set_next_sample_for_testing(int64_t next_sample)80void cordz_set_next_sample_for_testing(int64_t next_sample) { 81 cordz_next_sample = next_sample; 82 } 83 84 #endif // ABSL_INTERNAL_CORDZ_ENABLED 85 get_cordz_mean_interval()86int32_t get_cordz_mean_interval() { 87 return g_cordz_mean_interval.load(std::memory_order_acquire); 88 } 89 set_cordz_mean_interval(int32_t mean_interval)90void set_cordz_mean_interval(int32_t mean_interval) { 91 g_cordz_mean_interval.store(mean_interval, std::memory_order_release); 92 } 93 94 } // namespace cord_internal 95 ABSL_NAMESPACE_END 96 } // namespace absl 97