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