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 // TODO(b/162942788): weak 'cordz_disabled' value. 28 // A strong version is in the 'cordz_disabled_hack_for_odr' library which can 29 // be linked in to disable cordz at compile time. 30 extern "C" { 31 bool absl_internal_cordz_disabled ABSL_ATTRIBUTE_WEAK = false; 32 } 33 34 namespace absl { 35 ABSL_NAMESPACE_BEGIN 36 namespace cord_internal { 37 namespace { 38 39 // The average interval until the next sample. A value of 0 disables profiling 40 // while a value of 1 will profile all Cords. 41 std::atomic<int> g_cordz_mean_interval(50000); 42 43 } // namespace 44 45 #ifdef ABSL_INTERNAL_CORDZ_ENABLED 46 47 // Special negative 'not initialized' per thread value for cordz_next_sample. 48 static constexpr int64_t kInitCordzNextSample = -1; 49 50 ABSL_CONST_INIT thread_local int64_t cordz_next_sample = kInitCordzNextSample; 51 52 // kIntervalIfDisabled is the number of profile-eligible events need to occur 53 // before the code will confirm that cordz is still disabled. 54 constexpr int64_t kIntervalIfDisabled = 1 << 16; 55 cordz_should_profile_slow()56ABSL_ATTRIBUTE_NOINLINE bool cordz_should_profile_slow() { 57 // TODO(b/162942788): check if profiling is disabled at compile time. 58 if (absl_internal_cordz_disabled) { 59 ABSL_RAW_LOG(WARNING, "Cordz info disabled at compile time"); 60 // We are permanently disabled: set counter to highest possible value. 61 cordz_next_sample = std::numeric_limits<int64_t>::max(); 62 return false; 63 } 64 65 thread_local absl::base_internal::ExponentialBiased 66 exponential_biased_generator; 67 int32_t mean_interval = get_cordz_mean_interval(); 68 69 // Check if we disabled profiling. If so, set the next sample to a "large" 70 // number to minimize the overhead of the should_profile codepath. 71 if (mean_interval <= 0) { 72 cordz_next_sample = kIntervalIfDisabled; 73 return false; 74 } 75 76 // Check if we're always sampling. 77 if (mean_interval == 1) { 78 cordz_next_sample = 1; 79 return true; 80 } 81 82 if (cordz_next_sample <= 0) { 83 // If first check on current thread, check cordz_should_profile() 84 // again using the created (initial) stride in cordz_next_sample. 85 const bool initialized = cordz_next_sample != kInitCordzNextSample; 86 cordz_next_sample = exponential_biased_generator.GetStride(mean_interval); 87 return initialized || cordz_should_profile(); 88 } 89 90 --cordz_next_sample; 91 return false; 92 } 93 cordz_set_next_sample_for_testing(int64_t next_sample)94void cordz_set_next_sample_for_testing(int64_t next_sample) { 95 cordz_next_sample = next_sample; 96 } 97 98 #endif // ABSL_INTERNAL_CORDZ_ENABLED 99 get_cordz_mean_interval()100int32_t get_cordz_mean_interval() { 101 return g_cordz_mean_interval.load(std::memory_order_acquire); 102 } 103 set_cordz_mean_interval(int32_t mean_interval)104void set_cordz_mean_interval(int32_t mean_interval) { 105 g_cordz_mean_interval.store(mean_interval, std::memory_order_release); 106 } 107 108 } // namespace cord_internal 109 ABSL_NAMESPACE_END 110 } // namespace absl 111