Home | History | Annotate | Download | only in metrics
      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 "base/metrics/sparse_histogram.h"
      6 
      7 #include <utility>
      8 
      9 #include "base/metrics/metrics_hashes.h"
     10 #include "base/metrics/sample_map.h"
     11 #include "base/metrics/statistics_recorder.h"
     12 #include "base/pickle.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "base/synchronization/lock.h"
     15 
     16 namespace base {
     17 
     18 typedef HistogramBase::Count Count;
     19 typedef HistogramBase::Sample Sample;
     20 
     21 // static
     22 HistogramBase* SparseHistogram::FactoryGet(const std::string& name,
     23                                            int32_t flags) {
     24   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
     25 
     26   if (!histogram) {
     27     // To avoid racy destruction at shutdown, the following will be leaked.
     28     HistogramBase* tentative_histogram = new SparseHistogram(name);
     29     tentative_histogram->SetFlags(flags);
     30     histogram =
     31         StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
     32   }
     33   DCHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType());
     34   return histogram;
     35 }
     36 
     37 SparseHistogram::~SparseHistogram() {}
     38 
     39 uint64_t SparseHistogram::name_hash() const {
     40   return samples_.id();
     41 }
     42 
     43 HistogramType SparseHistogram::GetHistogramType() const {
     44   return SPARSE_HISTOGRAM;
     45 }
     46 
     47 bool SparseHistogram::HasConstructionArguments(
     48     Sample /* expected_minimum */,
     49     Sample /* expected_maximum */,
     50     size_t /* expected_bucket_count */) const {
     51   // SparseHistogram never has min/max/bucket_count limit.
     52   return false;
     53 }
     54 
     55 void SparseHistogram::Add(Sample value) {
     56   AddCount(value, 1);
     57 }
     58 
     59 void SparseHistogram::AddCount(Sample value, int count) {
     60   if (count <= 0) {
     61     NOTREACHED();
     62     return;
     63   }
     64   {
     65     base::AutoLock auto_lock(lock_);
     66     samples_.Accumulate(value, count);
     67   }
     68 
     69   FindAndRunCallback(value);
     70 }
     71 
     72 scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
     73   scoped_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
     74 
     75   base::AutoLock auto_lock(lock_);
     76   snapshot->Add(samples_);
     77   return std::move(snapshot);
     78 }
     79 
     80 void SparseHistogram::AddSamples(const HistogramSamples& samples) {
     81   base::AutoLock auto_lock(lock_);
     82   samples_.Add(samples);
     83 }
     84 
     85 bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) {
     86   base::AutoLock auto_lock(lock_);
     87   return samples_.AddFromPickle(iter);
     88 }
     89 
     90 void SparseHistogram::WriteHTMLGraph(std::string* output) const {
     91   output->append("<PRE>");
     92   WriteAsciiImpl(true, "<br>", output);
     93   output->append("</PRE>");
     94 }
     95 
     96 void SparseHistogram::WriteAscii(std::string* output) const {
     97   WriteAsciiImpl(true, "\n", output);
     98 }
     99 
    100 bool SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
    101   return pickle->WriteString(histogram_name()) && pickle->WriteInt(flags());
    102 }
    103 
    104 SparseHistogram::SparseHistogram(const std::string& name)
    105     : HistogramBase(name),
    106       samples_(HashMetricName(name)) {}
    107 
    108 HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
    109   std::string histogram_name;
    110   int flags;
    111   if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) {
    112     DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
    113     return NULL;
    114   }
    115 
    116   DCHECK(flags & HistogramBase::kIPCSerializationSourceFlag);
    117   flags &= ~HistogramBase::kIPCSerializationSourceFlag;
    118 
    119   return SparseHistogram::FactoryGet(histogram_name, flags);
    120 }
    121 
    122 void SparseHistogram::GetParameters(DictionaryValue* /* params */) const {
    123   // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
    124 }
    125 
    126 void SparseHistogram::GetCountAndBucketData(Count* /* count */,
    127                                             int64_t* /* sum */,
    128                                             ListValue* /* buckets */) const {
    129   // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
    130 }
    131 
    132 void SparseHistogram::WriteAsciiImpl(bool graph_it,
    133                                      const std::string& newline,
    134                                      std::string* output) const {
    135   // Get a local copy of the data so we are consistent.
    136   scoped_ptr<HistogramSamples> snapshot = SnapshotSamples();
    137   Count total_count = snapshot->TotalCount();
    138   double scaled_total_count = total_count / 100.0;
    139 
    140   WriteAsciiHeader(total_count, output);
    141   output->append(newline);
    142 
    143   // Determine how wide the largest bucket range is (how many digits to print),
    144   // so that we'll be able to right-align starts for the graphical bars.
    145   // Determine which bucket has the largest sample count so that we can
    146   // normalize the graphical bar-width relative to that sample count.
    147   Count largest_count = 0;
    148   Sample largest_sample = 0;
    149   scoped_ptr<SampleCountIterator> it = snapshot->Iterator();
    150   while (!it->Done()) {
    151     Sample min;
    152     Sample max;
    153     Count count;
    154     it->Get(&min, &max, &count);
    155     if (min > largest_sample)
    156       largest_sample = min;
    157     if (count > largest_count)
    158       largest_count = count;
    159     it->Next();
    160   }
    161   size_t print_width = GetSimpleAsciiBucketRange(largest_sample).size() + 1;
    162 
    163   // iterate over each item and display them
    164   it = snapshot->Iterator();
    165   while (!it->Done()) {
    166     Sample min;
    167     Sample max;
    168     Count count;
    169     it->Get(&min, &max, &count);
    170 
    171     // value is min, so display it
    172     std::string range = GetSimpleAsciiBucketRange(min);
    173     output->append(range);
    174     for (size_t j = 0; range.size() + j < print_width + 1; ++j)
    175       output->push_back(' ');
    176 
    177     if (graph_it)
    178       WriteAsciiBucketGraph(count, largest_count, output);
    179     WriteAsciiBucketValue(count, scaled_total_count, output);
    180     output->append(newline);
    181     it->Next();
    182   }
    183 }
    184 
    185 void SparseHistogram::WriteAsciiHeader(const Count total_count,
    186                                        std::string* output) const {
    187   StringAppendF(output,
    188                 "Histogram: %s recorded %d samples",
    189                 histogram_name().c_str(),
    190                 total_count);
    191   if (flags() & ~kHexRangePrintingFlag)
    192     StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
    193 }
    194 
    195 }  // namespace base
    196