// 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/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(); } ~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