• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <thread>  // NOLINT we need real clean new threads
18 
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 #include "absl/base/config.h"
22 
23 namespace absl {
24 ABSL_NAMESPACE_BEGIN
25 namespace cord_internal {
26 namespace {
27 
28 using ::testing::Eq;
29 using ::testing::Ge;
30 using ::testing::Le;
31 
TEST(CordzFunctionsTest,SampleRate)32 TEST(CordzFunctionsTest, SampleRate) {
33   int32_t orig_sample_rate = get_cordz_mean_interval();
34   int32_t expected_sample_rate = 123;
35   set_cordz_mean_interval(expected_sample_rate);
36   EXPECT_THAT(get_cordz_mean_interval(), Eq(expected_sample_rate));
37   set_cordz_mean_interval(orig_sample_rate);
38 }
39 
40 // Cordz is disabled when we don't have thread_local. All calls to
41 // should_profile will return false when cordz is disabled, so we might want to
42 // avoid those tests.
43 #ifdef ABSL_INTERNAL_CORDZ_ENABLED
44 
TEST(CordzFunctionsTest,ShouldProfileDisable)45 TEST(CordzFunctionsTest, ShouldProfileDisable) {
46   int32_t orig_sample_rate = get_cordz_mean_interval();
47 
48   set_cordz_mean_interval(0);
49   cordz_set_next_sample_for_testing(0);
50   EXPECT_EQ(cordz_should_profile(), 0);
51   // 1 << 16 is from kIntervalIfDisabled in cordz_functions.cc.
52   EXPECT_THAT(cordz_next_sample.next_sample, Eq(1 << 16));
53 
54   set_cordz_mean_interval(orig_sample_rate);
55 }
56 
TEST(CordzFunctionsTest,ShouldProfileAlways)57 TEST(CordzFunctionsTest, ShouldProfileAlways) {
58   int32_t orig_sample_rate = get_cordz_mean_interval();
59 
60   set_cordz_mean_interval(1);
61   cordz_set_next_sample_for_testing(1);
62   EXPECT_GT(cordz_should_profile(), 0);
63   EXPECT_THAT(cordz_next_sample.next_sample, Le(1));
64 
65   set_cordz_mean_interval(orig_sample_rate);
66 }
67 
TEST(CordzFunctionsTest,DoesNotAlwaysSampleFirstCord)68 TEST(CordzFunctionsTest, DoesNotAlwaysSampleFirstCord) {
69   // Set large enough interval such that the chance of 'tons' of threads
70   // randomly sampling the first call is infinitely small.
71   set_cordz_mean_interval(10000);
72   int tries = 0;
73   bool sampled = false;
74   do {
75     ++tries;
76     ASSERT_THAT(tries, Le(1000));
77     std::thread thread([&sampled] { sampled = cordz_should_profile() > 0; });
78     thread.join();
79   } while (sampled);
80 }
81 
TEST(CordzFunctionsTest,ShouldProfileRate)82 TEST(CordzFunctionsTest, ShouldProfileRate) {
83   static constexpr int kDesiredMeanInterval = 1000;
84   static constexpr int kSamples = 10000;
85   int32_t orig_sample_rate = get_cordz_mean_interval();
86 
87   set_cordz_mean_interval(kDesiredMeanInterval);
88 
89   int64_t sum_of_intervals = 0;
90   for (int i = 0; i < kSamples; i++) {
91     // Setting next_sample to 0 will force cordz_should_profile to generate a
92     // new value for next_sample each iteration.
93     cordz_set_next_sample_for_testing(0);
94     cordz_should_profile();
95     sum_of_intervals += cordz_next_sample.next_sample;
96   }
97 
98   // The sum of independent exponential variables is an Erlang distribution,
99   // which is a gamma distribution where the shape parameter is equal to the
100   // number of summands. The distribution used for cordz_should_profile is
101   // actually floor(Exponential(1/mean)) which introduces bias. However, we can
102   // apply the squint-really-hard correction factor. That is, when mean is
103   // large, then if we squint really hard the shape of the distribution between
104   // N and N+1 looks like a uniform distribution. On average, each value for
105   // next_sample will be about 0.5 lower than we would expect from an
106   // exponential distribution. This squint-really-hard correction approach won't
107   // work when mean is smaller than about 10 but works fine when mean is 1000.
108   //
109   // We can use R to calculate a confidence interval. This
110   // shows how to generate a confidence interval with a false positive rate of
111   // one in a billion.
112   //
113   // $ R -q
114   // > mean = 1000
115   // > kSamples = 10000
116   // > errorRate = 1e-9
117   // > correction = -kSamples / 2
118   // > low = qgamma(errorRate/2, kSamples, 1/mean) + correction
119   // > high = qgamma(1 - errorRate/2, kSamples, 1/mean) + correction
120   // > low
121   // [1] 9396115
122   // > high
123   // [1] 10618100
124   EXPECT_THAT(sum_of_intervals, Ge(9396115));
125   EXPECT_THAT(sum_of_intervals, Le(10618100));
126 
127   set_cordz_mean_interval(orig_sample_rate);
128 }
129 
130 #else  // ABSL_INTERNAL_CORDZ_ENABLED
131 
TEST(CordzFunctionsTest,ShouldProfileDisabled)132 TEST(CordzFunctionsTest, ShouldProfileDisabled) {
133   int32_t orig_sample_rate = get_cordz_mean_interval();
134 
135   set_cordz_mean_interval(1);
136   cordz_set_next_sample_for_testing(0);
137   EXPECT_FALSE(cordz_should_profile());
138 
139   set_cordz_mean_interval(orig_sample_rate);
140 }
141 
142 #endif  // ABSL_INTERNAL_CORDZ_ENABLED
143 
144 }  // namespace
145 }  // namespace cord_internal
146 ABSL_NAMESPACE_END
147 }  // namespace absl
148