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/histogram_base.h"
      6 
      7 #include <limits.h>
      8 
      9 #include <memory>
     10 #include <utility>
     11 
     12 #include "base/json/json_string_value_serializer.h"
     13 #include "base/logging.h"
     14 #include "base/metrics/histogram.h"
     15 #include "base/metrics/histogram_samples.h"
     16 #include "base/metrics/sparse_histogram.h"
     17 #include "base/metrics/statistics_recorder.h"
     18 #include "base/pickle.h"
     19 #include "base/process/process_handle.h"
     20 #include "base/strings/stringprintf.h"
     21 #include "base/values.h"
     22 
     23 namespace base {
     24 
     25 std::string HistogramTypeToString(HistogramType type) {
     26   switch (type) {
     27     case HISTOGRAM:
     28       return "HISTOGRAM";
     29     case LINEAR_HISTOGRAM:
     30       return "LINEAR_HISTOGRAM";
     31     case BOOLEAN_HISTOGRAM:
     32       return "BOOLEAN_HISTOGRAM";
     33     case CUSTOM_HISTOGRAM:
     34       return "CUSTOM_HISTOGRAM";
     35     case SPARSE_HISTOGRAM:
     36       return "SPARSE_HISTOGRAM";
     37   }
     38   NOTREACHED();
     39   return "UNKNOWN";
     40 }
     41 
     42 HistogramBase* DeserializeHistogramInfo(PickleIterator* iter) {
     43   int type;
     44   if (!iter->ReadInt(&type))
     45     return NULL;
     46 
     47   switch (type) {
     48     case HISTOGRAM:
     49       return Histogram::DeserializeInfoImpl(iter);
     50     case LINEAR_HISTOGRAM:
     51       return LinearHistogram::DeserializeInfoImpl(iter);
     52     case BOOLEAN_HISTOGRAM:
     53       return BooleanHistogram::DeserializeInfoImpl(iter);
     54     case CUSTOM_HISTOGRAM:
     55       return CustomHistogram::DeserializeInfoImpl(iter);
     56     case SPARSE_HISTOGRAM:
     57       return SparseHistogram::DeserializeInfoImpl(iter);
     58     default:
     59       return NULL;
     60   }
     61 }
     62 
     63 const HistogramBase::Sample HistogramBase::kSampleType_MAX = INT_MAX;
     64 HistogramBase* HistogramBase::report_histogram_ = nullptr;
     65 
     66 HistogramBase::HistogramBase(const std::string& name)
     67     : histogram_name_(name),
     68       flags_(kNoFlags) {}
     69 
     70 HistogramBase::~HistogramBase() {}
     71 
     72 void HistogramBase::CheckName(const StringPiece& name) const {
     73   DCHECK_EQ(histogram_name(), name);
     74 }
     75 
     76 void HistogramBase::SetFlags(int32_t flags) {
     77   HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
     78   subtle::NoBarrier_Store(&flags_, old_flags | flags);
     79 }
     80 
     81 void HistogramBase::ClearFlags(int32_t flags) {
     82   HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
     83   subtle::NoBarrier_Store(&flags_, old_flags & ~flags);
     84 }
     85 
     86 void HistogramBase::AddTime(const TimeDelta& time) {
     87   Add(static_cast<Sample>(time.InMilliseconds()));
     88 }
     89 
     90 void HistogramBase::AddBoolean(bool value) {
     91   Add(value ? 1 : 0);
     92 }
     93 
     94 bool HistogramBase::SerializeInfo(Pickle* pickle) const {
     95   if (!pickle->WriteInt(GetHistogramType()))
     96     return false;
     97   return SerializeInfoImpl(pickle);
     98 }
     99 
    100 uint32_t HistogramBase::FindCorruption(const HistogramSamples& samples) const {
    101   // Not supported by default.
    102   return NO_INCONSISTENCIES;
    103 }
    104 
    105 void HistogramBase::WriteJSON(std::string* output) const {
    106   Count count;
    107   int64_t sum;
    108   std::unique_ptr<ListValue> buckets(new ListValue());
    109   GetCountAndBucketData(&count, &sum, buckets.get());
    110   std::unique_ptr<DictionaryValue> parameters(new DictionaryValue());
    111   GetParameters(parameters.get());
    112 
    113   JSONStringValueSerializer serializer(output);
    114   DictionaryValue root;
    115   root.SetString("name", histogram_name());
    116   root.SetInteger("count", count);
    117   root.SetDouble("sum", static_cast<double>(sum));
    118   root.SetInteger("flags", flags());
    119   root.Set("params", std::move(parameters));
    120   root.Set("buckets", std::move(buckets));
    121   root.SetInteger("pid", GetUniqueIdForProcess());
    122   serializer.Serialize(root);
    123 }
    124 
    125 // static
    126 void HistogramBase::EnableActivityReportHistogram(
    127     const std::string& process_type) {
    128   if (report_histogram_)
    129     return;
    130 
    131   size_t existing = StatisticsRecorder::GetHistogramCount();
    132   if (existing != 0) {
    133     DVLOG(1) << existing
    134              << " histograms were created before reporting was enabled.";
    135   }
    136 
    137   std::string name =
    138       "UMA.Histograms.Activity" +
    139       (process_type.empty() ? process_type : "." + process_type);
    140 
    141   // Calling FactoryGet() here rather than using a histogram-macro works
    142   // around some problems with tests that could end up seeing the results
    143   // histogram when not expected due to a bad interaction between
    144   // HistogramTester and StatisticsRecorder.
    145   report_histogram_ = LinearHistogram::FactoryGet(
    146       name, 1, HISTOGRAM_REPORT_MAX, HISTOGRAM_REPORT_MAX + 1,
    147       kUmaTargetedHistogramFlag);
    148   report_histogram_->Add(HISTOGRAM_REPORT_CREATED);
    149 }
    150 
    151 void HistogramBase::FindAndRunCallback(HistogramBase::Sample sample) const {
    152   if ((flags() & kCallbackExists) == 0)
    153     return;
    154 
    155   StatisticsRecorder::OnSampleCallback cb =
    156       StatisticsRecorder::FindCallback(histogram_name());
    157   if (!cb.is_null())
    158     cb.Run(sample);
    159 }
    160 
    161 void HistogramBase::WriteAsciiBucketGraph(double current_size,
    162                                           double max_size,
    163                                           std::string* output) const {
    164   const int k_line_length = 72;  // Maximal horizontal width of graph.
    165   int x_count = static_cast<int>(k_line_length * (current_size / max_size)
    166                                  + 0.5);
    167   int x_remainder = k_line_length - x_count;
    168 
    169   while (0 < x_count--)
    170     output->append("-");
    171   output->append("O");
    172   while (0 < x_remainder--)
    173     output->append(" ");
    174 }
    175 
    176 const std::string HistogramBase::GetSimpleAsciiBucketRange(
    177     Sample sample) const {
    178   return StringPrintf("%d", sample);
    179 }
    180 
    181 void HistogramBase::WriteAsciiBucketValue(Count current,
    182                                           double scaled_sum,
    183                                           std::string* output) const {
    184   StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
    185 }
    186 
    187 // static
    188 void HistogramBase::ReportHistogramActivity(const HistogramBase& histogram,
    189                                             ReportActivity activity) {
    190   if (!report_histogram_)
    191     return;
    192 
    193   const int32_t flags = histogram.flags_;
    194   HistogramReport report_type = HISTOGRAM_REPORT_MAX;
    195   switch (activity) {
    196     case HISTOGRAM_CREATED:
    197       report_histogram_->Add(HISTOGRAM_REPORT_HISTOGRAM_CREATED);
    198       switch (histogram.GetHistogramType()) {
    199         case HISTOGRAM:
    200           report_type = HISTOGRAM_REPORT_TYPE_LOGARITHMIC;
    201           break;
    202         case LINEAR_HISTOGRAM:
    203           report_type = HISTOGRAM_REPORT_TYPE_LINEAR;
    204           break;
    205         case BOOLEAN_HISTOGRAM:
    206           report_type = HISTOGRAM_REPORT_TYPE_BOOLEAN;
    207           break;
    208         case CUSTOM_HISTOGRAM:
    209           report_type = HISTOGRAM_REPORT_TYPE_CUSTOM;
    210           break;
    211         case SPARSE_HISTOGRAM:
    212           report_type = HISTOGRAM_REPORT_TYPE_SPARSE;
    213           break;
    214       }
    215       report_histogram_->Add(report_type);
    216       if (flags & kIsPersistent)
    217         report_histogram_->Add(HISTOGRAM_REPORT_FLAG_PERSISTENT);
    218       if ((flags & kUmaStabilityHistogramFlag) == kUmaStabilityHistogramFlag)
    219         report_histogram_->Add(HISTOGRAM_REPORT_FLAG_UMA_STABILITY);
    220       else if (flags & kUmaTargetedHistogramFlag)
    221         report_histogram_->Add(HISTOGRAM_REPORT_FLAG_UMA_TARGETED);
    222       break;
    223 
    224     case HISTOGRAM_LOOKUP:
    225       report_histogram_->Add(HISTOGRAM_REPORT_HISTOGRAM_LOOKUP);
    226       break;
    227   }
    228 }
    229 
    230 }  // namespace base
    231