Home | History | Annotate | Download | only in metrics
      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