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