| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include <vector> | |
| #include "base/metrics/histogram.h" | |
| #include "base/metrics/histogram_base.h" | |
| #include "base/metrics/persistent_histogram_allocator.h" | |
| #include "base/metrics/sample_vector.h" | |
| #include "base/metrics/sparse_histogram.h" | |
| #include "base/metrics/statistics_recorder.h" | |
| #include "base/pickle.h" | |
| #include "testing/gtest/include/gtest/gtest.h" | |
| namespace base { | |
| class HistogramBaseTest : public testing::Test { | |
| protected: | |
| HistogramBaseTest() { | |
| // Each test will have a clean state (no Histogram / BucketRanges | |
| // registered). | |
| ResetStatisticsRecorder(); | |
| GlobalHistogramAllocator::ReleaseForTesting(); | |
| } | |
| ~HistogramBaseTest() override = default; | |
| void ResetStatisticsRecorder() { | |
| // It is necessary to fully destruct any existing StatisticsRecorder | |
| // before creating a new one. | |
| statistics_recorder_.reset(); | |
| statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting(); | |
| } | |
| private: | |
| std::unique_ptr<StatisticsRecorder> statistics_recorder_; | |
| DISALLOW_COPY_AND_ASSIGN(HistogramBaseTest); | |
| }; | |
| TEST_F(HistogramBaseTest, DeserializeHistogram) { | |
| HistogramBase* histogram = Histogram::FactoryGet( | |
| "TestHistogram", 1, 1000, 10, | |
| (HistogramBase::kUmaTargetedHistogramFlag | | |
| HistogramBase::kIPCSerializationSourceFlag)); | |
| Pickle pickle; | |
| histogram->SerializeInfo(&pickle); | |
| PickleIterator iter(pickle); | |
| HistogramBase* deserialized = DeserializeHistogramInfo(&iter); | |
| EXPECT_EQ(histogram, deserialized); | |
| ResetStatisticsRecorder(); | |
| PickleIterator iter2(pickle); | |
| deserialized = DeserializeHistogramInfo(&iter2); | |
| EXPECT_TRUE(deserialized); | |
| EXPECT_NE(histogram, deserialized); | |
| EXPECT_EQ("TestHistogram", StringPiece(deserialized->histogram_name())); | |
| EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10)); | |
| // kIPCSerializationSourceFlag will be cleared. | |
| EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, deserialized->flags()); | |
| } | |
| TEST_F(HistogramBaseTest, DeserializeLinearHistogram) { | |
| HistogramBase* histogram = LinearHistogram::FactoryGet( | |
| "TestHistogram", 1, 1000, 10, | |
| HistogramBase::kIPCSerializationSourceFlag); | |
| Pickle pickle; | |
| histogram->SerializeInfo(&pickle); | |
| PickleIterator iter(pickle); | |
| HistogramBase* deserialized = DeserializeHistogramInfo(&iter); | |
| EXPECT_EQ(histogram, deserialized); | |
| ResetStatisticsRecorder(); | |
| PickleIterator iter2(pickle); | |
| deserialized = DeserializeHistogramInfo(&iter2); | |
| EXPECT_TRUE(deserialized); | |
| EXPECT_NE(histogram, deserialized); | |
| EXPECT_EQ("TestHistogram", StringPiece(deserialized->histogram_name())); | |
| EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10)); | |
| EXPECT_EQ(0, deserialized->flags()); | |
| } | |
| TEST_F(HistogramBaseTest, DeserializeBooleanHistogram) { | |
| HistogramBase* histogram = BooleanHistogram::FactoryGet( | |
| "TestHistogram", HistogramBase::kIPCSerializationSourceFlag); | |
| Pickle pickle; | |
| histogram->SerializeInfo(&pickle); | |
| PickleIterator iter(pickle); | |
| HistogramBase* deserialized = DeserializeHistogramInfo(&iter); | |
| EXPECT_EQ(histogram, deserialized); | |
| ResetStatisticsRecorder(); | |
| PickleIterator iter2(pickle); | |
| deserialized = DeserializeHistogramInfo(&iter2); | |
| EXPECT_TRUE(deserialized); | |
| EXPECT_NE(histogram, deserialized); | |
| EXPECT_EQ("TestHistogram", StringPiece(deserialized->histogram_name())); | |
| EXPECT_TRUE(deserialized->HasConstructionArguments(1, 2, 3)); | |
| EXPECT_EQ(0, deserialized->flags()); | |
| } | |
| TEST_F(HistogramBaseTest, DeserializeCustomHistogram) { | |
| std::vector<HistogramBase::Sample> ranges; | |
| ranges.push_back(13); | |
| ranges.push_back(5); | |
| ranges.push_back(9); | |
| HistogramBase* histogram = CustomHistogram::FactoryGet( | |
| "TestHistogram", ranges, HistogramBase::kIPCSerializationSourceFlag); | |
| Pickle pickle; | |
| histogram->SerializeInfo(&pickle); | |
| PickleIterator iter(pickle); | |
| HistogramBase* deserialized = DeserializeHistogramInfo(&iter); | |
| EXPECT_EQ(histogram, deserialized); | |
| ResetStatisticsRecorder(); | |
| PickleIterator iter2(pickle); | |
| deserialized = DeserializeHistogramInfo(&iter2); | |
| EXPECT_TRUE(deserialized); | |
| EXPECT_NE(histogram, deserialized); | |
| EXPECT_EQ("TestHistogram", StringPiece(deserialized->histogram_name())); | |
| EXPECT_TRUE(deserialized->HasConstructionArguments(5, 13, 4)); | |
| EXPECT_EQ(0, deserialized->flags()); | |
| } | |
| TEST_F(HistogramBaseTest, DeserializeSparseHistogram) { | |
| HistogramBase* histogram = SparseHistogram::FactoryGet( | |
| "TestHistogram", HistogramBase::kIPCSerializationSourceFlag); | |
| Pickle pickle; | |
| histogram->SerializeInfo(&pickle); | |
| PickleIterator iter(pickle); | |
| HistogramBase* deserialized = DeserializeHistogramInfo(&iter); | |
| EXPECT_EQ(histogram, deserialized); | |
| ResetStatisticsRecorder(); | |
| PickleIterator iter2(pickle); | |
| deserialized = DeserializeHistogramInfo(&iter2); | |
| EXPECT_TRUE(deserialized); | |
| EXPECT_NE(histogram, deserialized); | |
| EXPECT_EQ("TestHistogram", StringPiece(deserialized->histogram_name())); | |
| EXPECT_EQ(0, deserialized->flags()); | |
| } | |
| TEST_F(HistogramBaseTest, AddKilo) { | |
| HistogramBase* histogram = | |
| LinearHistogram::FactoryGet("TestAddKiloHistogram", 1, 1000, 100, 0); | |
| histogram->AddKilo(100, 1000); | |
| histogram->AddKilo(200, 2000); | |
| histogram->AddKilo(300, 1500); | |
| std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); | |
| EXPECT_EQ(1, samples->GetCount(100)); | |
| EXPECT_EQ(2, samples->GetCount(200)); | |
| EXPECT_LE(1, samples->GetCount(300)); | |
| EXPECT_GE(2, samples->GetCount(300)); | |
| } | |
| TEST_F(HistogramBaseTest, AddKiB) { | |
| HistogramBase* histogram = | |
| LinearHistogram::FactoryGet("TestAddKiBHistogram", 1, 1000, 100, 0); | |
| histogram->AddKiB(100, 1024); | |
| histogram->AddKiB(200, 2048); | |
| histogram->AddKiB(300, 1536); | |
| std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); | |
| EXPECT_EQ(1, samples->GetCount(100)); | |
| EXPECT_EQ(2, samples->GetCount(200)); | |
| EXPECT_LE(1, samples->GetCount(300)); | |
| EXPECT_GE(2, samples->GetCount(300)); | |
| } | |
| TEST_F(HistogramBaseTest, AddTimeMillisecondsGranularityOverflow) { | |
| const HistogramBase::Sample sample_max = | |
| std::numeric_limits<HistogramBase::Sample>::max() / 2; | |
| HistogramBase* histogram = LinearHistogram::FactoryGet( | |
| "TestAddTimeMillisecondsGranularity1", 1, sample_max, 100, 0); | |
| int64_t large_positive = std::numeric_limits<int64_t>::max(); | |
| // |add_count| is the number of large values that have been added to the | |
| // histogram. We consider a number to be 'large' if it cannot be represented | |
| // in a HistogramBase::Sample. | |
| int add_count = 0; | |
| while (large_positive > std::numeric_limits<HistogramBase::Sample>::max()) { | |
| // Add the TimeDelta corresponding to |large_positive| milliseconds to the | |
| // histogram. | |
| histogram->AddTimeMillisecondsGranularity( | |
| TimeDelta::FromMilliseconds(large_positive)); | |
| ++add_count; | |
| // Reduce the value of |large_positive|. The choice of 7 here is | |
| // arbitrary. | |
| large_positive /= 7; | |
| } | |
| std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); | |
| // All of the reported values must have gone into the max overflow bucket. | |
| EXPECT_EQ(add_count, samples->GetCount(sample_max)); | |
| // We now perform the analoguous operations, now with negative values with a | |
| // large absolute value. | |
| histogram = LinearHistogram::FactoryGet("TestAddTimeMillisecondsGranularity2", | |
| 1, sample_max, 100, 0); | |
| int64_t large_negative = std::numeric_limits<int64_t>::min(); | |
| add_count = 0; | |
| while (large_negative < std::numeric_limits<HistogramBase::Sample>::min()) { | |
| histogram->AddTimeMillisecondsGranularity( | |
| TimeDelta::FromMilliseconds(large_negative)); | |
| ++add_count; | |
| large_negative /= 7; | |
| } | |
| samples = histogram->SnapshotSamples(); | |
| // All of the reported values must have gone into the min overflow bucket. | |
| EXPECT_EQ(add_count, samples->GetCount(0)); | |
| } | |
| TEST_F(HistogramBaseTest, AddTimeMicrosecondsGranularityOverflow) { | |
| // Nothing to test if we don't have a high resolution clock. | |
| if (!TimeTicks::IsHighResolution()) | |
| return; | |
| const HistogramBase::Sample sample_max = | |
| std::numeric_limits<HistogramBase::Sample>::max() / 2; | |
| HistogramBase* histogram = LinearHistogram::FactoryGet( | |
| "TestAddTimeMicrosecondsGranularity1", 1, sample_max, 100, 0); | |
| int64_t large_positive = std::numeric_limits<int64_t>::max(); | |
| // |add_count| is the number of large values that have been added to the | |
| // histogram. We consider a number to be 'large' if it cannot be represented | |
| // in a HistogramBase::Sample. | |
| int add_count = 0; | |
| while (large_positive > std::numeric_limits<HistogramBase::Sample>::max()) { | |
| // Add the TimeDelta corresponding to |large_positive| microseconds to the | |
| // histogram. | |
| histogram->AddTimeMicrosecondsGranularity( | |
| TimeDelta::FromMicroseconds(large_positive)); | |
| ++add_count; | |
| // Reduce the value of |large_positive|. The choice of 7 here is | |
| // arbitrary. | |
| large_positive /= 7; | |
| } | |
| std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); | |
| // All of the reported values must have gone into the max overflow bucket. | |
| EXPECT_EQ(add_count, samples->GetCount(sample_max)); | |
| // We now perform the analoguous operations, now with negative values with a | |
| // large absolute value. | |
| histogram = LinearHistogram::FactoryGet("TestAddTimeMicrosecondsGranularity2", | |
| 1, sample_max, 100, 0); | |
| int64_t large_negative = std::numeric_limits<int64_t>::min(); | |
| add_count = 0; | |
| while (large_negative < std::numeric_limits<HistogramBase::Sample>::min()) { | |
| histogram->AddTimeMicrosecondsGranularity( | |
| TimeDelta::FromMicroseconds(large_negative)); | |
| ++add_count; | |
| large_negative /= 7; | |
| } | |
| samples = histogram->SnapshotSamples(); | |
| // All of the reported values must have gone into the min overflow bucket. | |
| EXPECT_EQ(add_count, samples->GetCount(0)); | |
| } | |
| } // namespace base |