1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/metrics/histogram_base.h"
6
7 #include <limits>
8 #include <string_view>
9 #include <vector>
10
11 #include "base/metrics/histogram.h"
12 #include "base/metrics/sample_vector.h"
13 #include "base/metrics/sparse_histogram.h"
14 #include "base/metrics/statistics_recorder.h"
15 #include "base/pickle.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace base {
19
20 class HistogramBaseTest : public testing::Test {
21 public:
HistogramBaseTest()22 HistogramBaseTest() {
23 // Each test will have a clean state (no Histogram / BucketRanges
24 // registered).
25 ResetStatisticsRecorder();
26 }
27
28 HistogramBaseTest(const HistogramBaseTest&) = delete;
29 HistogramBaseTest& operator=(const HistogramBaseTest&) = delete;
30 ~HistogramBaseTest() override = default;
31
32 protected:
ResetStatisticsRecorder()33 void ResetStatisticsRecorder() {
34 // It is necessary to fully destruct any existing StatisticsRecorder
35 // before creating a new one.
36 statistics_recorder_.reset();
37 statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting();
38 }
39
40 private:
41 std::unique_ptr<StatisticsRecorder> statistics_recorder_;
42 };
43
TEST_F(HistogramBaseTest,DeserializeHistogram)44 TEST_F(HistogramBaseTest, DeserializeHistogram) {
45 HistogramBase* histogram = Histogram::FactoryGet(
46 "TestHistogram", 1, 1000, 10,
47 (HistogramBase::kUmaTargetedHistogramFlag |
48 HistogramBase::kIPCSerializationSourceFlag));
49
50 Pickle pickle;
51 histogram->SerializeInfo(&pickle);
52
53 PickleIterator iter(pickle);
54 HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
55 EXPECT_EQ(histogram, deserialized);
56
57 ResetStatisticsRecorder();
58
59 PickleIterator iter2(pickle);
60 deserialized = DeserializeHistogramInfo(&iter2);
61 EXPECT_TRUE(deserialized);
62 EXPECT_NE(histogram, deserialized);
63 EXPECT_STREQ("TestHistogram", deserialized->histogram_name());
64 EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10));
65
66 // kIPCSerializationSourceFlag will be cleared.
67 EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, deserialized->flags());
68 }
69
TEST_F(HistogramBaseTest,DeserializeLinearHistogram)70 TEST_F(HistogramBaseTest, DeserializeLinearHistogram) {
71 HistogramBase* histogram = LinearHistogram::FactoryGet(
72 "TestHistogram", 1, 1000, 10,
73 HistogramBase::kIPCSerializationSourceFlag);
74
75 Pickle pickle;
76 histogram->SerializeInfo(&pickle);
77
78 PickleIterator iter(pickle);
79 HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
80 EXPECT_EQ(histogram, deserialized);
81
82 ResetStatisticsRecorder();
83
84 PickleIterator iter2(pickle);
85 deserialized = DeserializeHistogramInfo(&iter2);
86 EXPECT_TRUE(deserialized);
87 EXPECT_NE(histogram, deserialized);
88 EXPECT_STREQ("TestHistogram", deserialized->histogram_name());
89 EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10));
90 EXPECT_EQ(0, deserialized->flags());
91 }
92
TEST_F(HistogramBaseTest,DeserializeBooleanHistogram)93 TEST_F(HistogramBaseTest, DeserializeBooleanHistogram) {
94 HistogramBase* histogram = BooleanHistogram::FactoryGet(
95 "TestHistogram", HistogramBase::kIPCSerializationSourceFlag);
96
97 Pickle pickle;
98 histogram->SerializeInfo(&pickle);
99
100 PickleIterator iter(pickle);
101 HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
102 EXPECT_EQ(histogram, deserialized);
103
104 ResetStatisticsRecorder();
105
106 PickleIterator iter2(pickle);
107 deserialized = DeserializeHistogramInfo(&iter2);
108 EXPECT_TRUE(deserialized);
109 EXPECT_NE(histogram, deserialized);
110 EXPECT_STREQ("TestHistogram", deserialized->histogram_name());
111 EXPECT_TRUE(deserialized->HasConstructionArguments(1, 2, 3));
112 EXPECT_EQ(0, deserialized->flags());
113 }
114
TEST_F(HistogramBaseTest,DeserializeCustomHistogram)115 TEST_F(HistogramBaseTest, DeserializeCustomHistogram) {
116 std::vector<HistogramBase::Sample> ranges;
117 ranges.push_back(13);
118 ranges.push_back(5);
119 ranges.push_back(9);
120
121 HistogramBase* histogram = CustomHistogram::FactoryGet(
122 "TestHistogram", ranges, HistogramBase::kIPCSerializationSourceFlag);
123
124 Pickle pickle;
125 histogram->SerializeInfo(&pickle);
126
127 PickleIterator iter(pickle);
128 HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
129 EXPECT_EQ(histogram, deserialized);
130
131 ResetStatisticsRecorder();
132
133 PickleIterator iter2(pickle);
134 deserialized = DeserializeHistogramInfo(&iter2);
135 EXPECT_TRUE(deserialized);
136 EXPECT_NE(histogram, deserialized);
137 EXPECT_STREQ("TestHistogram", deserialized->histogram_name());
138 EXPECT_TRUE(deserialized->HasConstructionArguments(5, 13, 4));
139 EXPECT_EQ(0, deserialized->flags());
140 }
141
TEST_F(HistogramBaseTest,DeserializeSparseHistogram)142 TEST_F(HistogramBaseTest, DeserializeSparseHistogram) {
143 HistogramBase* histogram = SparseHistogram::FactoryGet(
144 "TestHistogram", HistogramBase::kIPCSerializationSourceFlag);
145
146 Pickle pickle;
147 histogram->SerializeInfo(&pickle);
148
149 PickleIterator iter(pickle);
150 HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
151 EXPECT_EQ(histogram, deserialized);
152
153 ResetStatisticsRecorder();
154
155 PickleIterator iter2(pickle);
156 deserialized = DeserializeHistogramInfo(&iter2);
157 EXPECT_TRUE(deserialized);
158 EXPECT_NE(histogram, deserialized);
159 EXPECT_STREQ("TestHistogram", deserialized->histogram_name());
160 EXPECT_EQ(0, deserialized->flags());
161 }
162
TEST_F(HistogramBaseTest,AddKilo)163 TEST_F(HistogramBaseTest, AddKilo) {
164 HistogramBase* histogram =
165 LinearHistogram::FactoryGet("TestAddKiloHistogram", 1, 1000, 100, 0);
166
167 histogram->AddKilo(100, 1000);
168 histogram->AddKilo(200, 2000);
169 histogram->AddKilo(300, 1500);
170
171 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
172 EXPECT_EQ(1, samples->GetCount(100));
173 EXPECT_EQ(2, samples->GetCount(200));
174 EXPECT_LE(1, samples->GetCount(300));
175 EXPECT_GE(2, samples->GetCount(300));
176 }
177
TEST_F(HistogramBaseTest,AddKiB)178 TEST_F(HistogramBaseTest, AddKiB) {
179 HistogramBase* histogram =
180 LinearHistogram::FactoryGet("TestAddKiBHistogram", 1, 1000, 100, 0);
181
182 histogram->AddKiB(100, 1024);
183 histogram->AddKiB(200, 2048);
184 histogram->AddKiB(300, 1536);
185
186 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
187 EXPECT_EQ(1, samples->GetCount(100));
188 EXPECT_EQ(2, samples->GetCount(200));
189 EXPECT_LE(1, samples->GetCount(300));
190 EXPECT_GE(2, samples->GetCount(300));
191 }
192
TEST_F(HistogramBaseTest,AddTimeMillisecondsGranularityOverflow)193 TEST_F(HistogramBaseTest, AddTimeMillisecondsGranularityOverflow) {
194 const HistogramBase::Sample sample_max =
195 std::numeric_limits<HistogramBase::Sample>::max() / 2;
196 HistogramBase* histogram = LinearHistogram::FactoryGet(
197 "TestAddTimeMillisecondsGranularity1", 1, sample_max, 100, 0);
198 int64_t large_positive = std::numeric_limits<int64_t>::max();
199 // |add_count| is the number of large values that have been added to the
200 // histogram. We consider a number to be 'large' if it cannot be represented
201 // in a HistogramBase::Sample.
202 int add_count = 0;
203 while (large_positive > std::numeric_limits<HistogramBase::Sample>::max()) {
204 // Add the TimeDelta corresponding to |large_positive| milliseconds to the
205 // histogram.
206 histogram->AddTimeMillisecondsGranularity(Milliseconds(large_positive));
207 ++add_count;
208 // Reduce the value of |large_positive|. The choice of 7 here is
209 // arbitrary.
210 large_positive /= 7;
211 }
212 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
213 // All of the reported values must have gone into the max overflow bucket.
214 EXPECT_EQ(add_count, samples->GetCount(sample_max));
215
216 // We now perform the analoguous operations, now with negative values with a
217 // large absolute value.
218 histogram = LinearHistogram::FactoryGet("TestAddTimeMillisecondsGranularity2",
219 1, sample_max, 100, 0);
220 int64_t large_negative = std::numeric_limits<int64_t>::min();
221 add_count = 0;
222 while (large_negative < std::numeric_limits<HistogramBase::Sample>::min()) {
223 histogram->AddTimeMillisecondsGranularity(Milliseconds(large_negative));
224 ++add_count;
225 large_negative /= 7;
226 }
227 samples = histogram->SnapshotSamples();
228 // All of the reported values must have gone into the min overflow bucket.
229 EXPECT_EQ(add_count, samples->GetCount(0));
230 }
231
TEST_F(HistogramBaseTest,AddTimeMicrosecondsGranularityOverflow)232 TEST_F(HistogramBaseTest, AddTimeMicrosecondsGranularityOverflow) {
233 // Nothing to test if we don't have a high resolution clock.
234 if (!TimeTicks::IsHighResolution())
235 return;
236
237 const HistogramBase::Sample sample_max =
238 std::numeric_limits<HistogramBase::Sample>::max() / 2;
239 HistogramBase* histogram = LinearHistogram::FactoryGet(
240 "TestAddTimeMicrosecondsGranularity1", 1, sample_max, 100, 0);
241 int64_t large_positive = std::numeric_limits<int64_t>::max();
242 // |add_count| is the number of large values that have been added to the
243 // histogram. We consider a number to be 'large' if it cannot be represented
244 // in a HistogramBase::Sample.
245 int add_count = 0;
246 while (large_positive > std::numeric_limits<HistogramBase::Sample>::max()) {
247 // Add the TimeDelta corresponding to |large_positive| microseconds to the
248 // histogram.
249 histogram->AddTimeMicrosecondsGranularity(Microseconds(large_positive));
250 ++add_count;
251 // Reduce the value of |large_positive|. The choice of 7 here is
252 // arbitrary.
253 large_positive /= 7;
254 }
255 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
256 // All of the reported values must have gone into the max overflow bucket.
257 EXPECT_EQ(add_count, samples->GetCount(sample_max));
258
259 // We now perform the analoguous operations, now with negative values with a
260 // large absolute value.
261 histogram = LinearHistogram::FactoryGet("TestAddTimeMicrosecondsGranularity2",
262 1, sample_max, 100, 0);
263 int64_t large_negative = std::numeric_limits<int64_t>::min();
264 add_count = 0;
265 while (large_negative < std::numeric_limits<HistogramBase::Sample>::min()) {
266 histogram->AddTimeMicrosecondsGranularity(Microseconds(large_negative));
267 ++add_count;
268 large_negative /= 7;
269 }
270 samples = histogram->SnapshotSamples();
271 // All of the reported values must have gone into the min overflow bucket.
272 EXPECT_EQ(add_count, samples->GetCount(0));
273 }
274
275 } // namespace base
276