1 // Copyright 2014 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 "base/test/metrics/histogram_tester.h" 6 7 #include <stddef.h> 8 9 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram_samples.h" 11 #include "base/metrics/metrics_hashes.h" 12 #include "base/metrics/sample_map.h" 13 #include "base/metrics/sparse_histogram.h" 14 #include "base/metrics/statistics_recorder.h" 15 #include "base/strings/string_util.h" 16 #include "base/strings/stringprintf.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 19 namespace base { 20 21 HistogramTester::HistogramTester() { 22 // Record any histogram data that exists when the object is created so it can 23 // be subtracted later. 24 for (const auto* const histogram : StatisticsRecorder::GetHistograms()) { 25 histograms_snapshot_[histogram->histogram_name()] = 26 histogram->SnapshotSamples(); 27 } 28 } 29 30 HistogramTester::~HistogramTester() = default; 31 32 void HistogramTester::ExpectUniqueSample( 33 const std::string& name, 34 HistogramBase::Sample sample, 35 HistogramBase::Count expected_count) const { 36 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); 37 EXPECT_NE(nullptr, histogram) 38 << "Histogram \"" << name << "\" does not exist."; 39 40 if (histogram) { 41 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); 42 CheckBucketCount(name, sample, expected_count, *samples); 43 CheckTotalCount(name, expected_count, *samples); 44 } 45 } 46 47 void HistogramTester::ExpectBucketCount( 48 const std::string& name, 49 HistogramBase::Sample sample, 50 HistogramBase::Count expected_count) const { 51 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); 52 EXPECT_NE(nullptr, histogram) 53 << "Histogram \"" << name << "\" does not exist."; 54 55 if (histogram) { 56 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); 57 CheckBucketCount(name, sample, expected_count, *samples); 58 } 59 } 60 61 void HistogramTester::ExpectTotalCount(const std::string& name, 62 HistogramBase::Count count) const { 63 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); 64 if (histogram) { 65 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); 66 CheckTotalCount(name, count, *samples); 67 } else { 68 // No histogram means there were zero samples. 69 EXPECT_EQ(count, 0) << "Histogram \"" << name << "\" does not exist."; 70 } 71 } 72 73 void HistogramTester::ExpectTimeBucketCount(const std::string& name, 74 TimeDelta sample, 75 HistogramBase::Count count) const { 76 ExpectBucketCount(name, sample.InMilliseconds(), count); 77 } 78 79 std::vector<Bucket> HistogramTester::GetAllSamples( 80 const std::string& name) const { 81 std::vector<Bucket> samples; 82 std::unique_ptr<HistogramSamples> snapshot = 83 GetHistogramSamplesSinceCreation(name); 84 if (snapshot) { 85 for (auto it = snapshot->Iterator(); !it->Done(); it->Next()) { 86 HistogramBase::Sample sample; 87 HistogramBase::Count count; 88 it->Get(&sample, nullptr, &count); 89 samples.push_back(Bucket(sample, count)); 90 } 91 } 92 return samples; 93 } 94 95 HistogramBase::Count HistogramTester::GetBucketCount( 96 const std::string& name, 97 HistogramBase::Sample sample) const { 98 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); 99 EXPECT_NE(nullptr, histogram) 100 << "Histogram \"" << name << "\" does not exist."; 101 HistogramBase::Count count = 0; 102 if (histogram) { 103 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); 104 GetBucketCountForSamples(name, sample, *samples, &count); 105 } 106 return count; 107 } 108 109 void HistogramTester::GetBucketCountForSamples( 110 const std::string& name, 111 HistogramBase::Sample sample, 112 const HistogramSamples& samples, 113 HistogramBase::Count* count) const { 114 *count = samples.GetCount(sample); 115 auto histogram_data = histograms_snapshot_.find(name); 116 if (histogram_data != histograms_snapshot_.end()) 117 *count -= histogram_data->second->GetCount(sample); 118 } 119 120 HistogramTester::CountsMap HistogramTester::GetTotalCountsForPrefix( 121 const std::string& prefix) const { 122 EXPECT_TRUE(prefix.find('.') != std::string::npos) 123 << "|prefix| ought to contain at least one period, to avoid matching too" 124 << " many histograms."; 125 126 CountsMap result; 127 128 // Find candidate matches by using the logic built into GetSnapshot(). 129 for (const HistogramBase* histogram : StatisticsRecorder::GetHistograms()) { 130 if (!StartsWith(histogram->histogram_name(), prefix, 131 CompareCase::SENSITIVE)) { 132 continue; 133 } 134 std::unique_ptr<HistogramSamples> new_samples = 135 GetHistogramSamplesSinceCreation(histogram->histogram_name()); 136 // Omit unchanged histograms from the result. 137 if (new_samples->TotalCount()) { 138 result[histogram->histogram_name()] = new_samples->TotalCount(); 139 } 140 } 141 return result; 142 } 143 144 std::unique_ptr<HistogramSamples> 145 HistogramTester::GetHistogramSamplesSinceCreation( 146 const std::string& histogram_name) const { 147 HistogramBase* histogram = StatisticsRecorder::FindHistogram(histogram_name); 148 // Whether the histogram exists or not may not depend on the current test 149 // calling this method, but rather on which tests ran before and possibly 150 // generated a histogram or not (see http://crbug.com/473689). To provide a 151 // response which is independent of the previously run tests, this method 152 // creates empty samples in the absence of the histogram, rather than 153 // returning null. 154 if (!histogram) { 155 return std::unique_ptr<HistogramSamples>( 156 new SampleMap(HashMetricName(histogram_name))); 157 } 158 std::unique_ptr<HistogramSamples> named_samples = 159 histogram->SnapshotSamples(); 160 auto original_samples_it = histograms_snapshot_.find(histogram_name); 161 if (original_samples_it != histograms_snapshot_.end()) 162 named_samples->Subtract(*original_samples_it->second.get()); 163 return named_samples; 164 } 165 166 std::string HistogramTester::GetAllHistogramsRecorded() const { 167 std::string output; 168 169 for (const auto* const histogram : StatisticsRecorder::GetHistograms()) { 170 std::unique_ptr<HistogramSamples> named_samples = 171 histogram->SnapshotSamples(); 172 173 for (const auto& histogram_data : histograms_snapshot_) { 174 if (histogram_data.first == histogram->histogram_name()) 175 named_samples->Subtract(*histogram_data.second); 176 } 177 178 if (named_samples->TotalCount()) { 179 auto current_count = histogram->SnapshotSamples()->TotalCount(); 180 StringAppendF(&output, "Histogram: %s recorded %d new samples.\n", 181 histogram->histogram_name(), named_samples->TotalCount()); 182 if (current_count != named_samples->TotalCount()) { 183 StringAppendF(&output, 184 "WARNING: There were samples recorded to this histogram " 185 "before tester instantiation.\n"); 186 } 187 histogram->WriteAscii(&output); 188 StringAppendF(&output, "\n"); 189 } 190 } 191 192 return output; 193 } 194 195 void HistogramTester::CheckBucketCount(const std::string& name, 196 HistogramBase::Sample sample, 197 HistogramBase::Count expected_count, 198 const HistogramSamples& samples) const { 199 int actual_count; 200 GetBucketCountForSamples(name, sample, samples, &actual_count); 201 202 EXPECT_EQ(expected_count, actual_count) 203 << "Histogram \"" << name 204 << "\" does not have the right number of samples (" << expected_count 205 << ") in the expected bucket (" << sample << "). It has (" << actual_count 206 << ")."; 207 } 208 209 void HistogramTester::CheckTotalCount(const std::string& name, 210 HistogramBase::Count expected_count, 211 const HistogramSamples& samples) const { 212 int actual_count = samples.TotalCount(); 213 auto histogram_data = histograms_snapshot_.find(name); 214 if (histogram_data != histograms_snapshot_.end()) 215 actual_count -= histogram_data->second->TotalCount(); 216 217 EXPECT_EQ(expected_count, actual_count) 218 << "Histogram \"" << name 219 << "\" does not have the right total number of samples (" 220 << expected_count << "). It has (" << actual_count << ")."; 221 } 222 223 bool Bucket::operator==(const Bucket& other) const { 224 return min == other.min && count == other.count; 225 } 226 227 void PrintTo(const Bucket& bucket, std::ostream* os) { 228 *os << "Bucket " << bucket.min << ": " << bucket.count; 229 } 230 231 } // namespace base 232