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 <set>
     11 #include <utility>
     12 
     13 #include "base/json/json_string_value_serializer.h"
     14 #include "base/lazy_instance.h"
     15 #include "base/logging.h"
     16 #include "base/metrics/histogram.h"
     17 #include "base/metrics/histogram_macros.h"
     18 #include "base/metrics/histogram_samples.h"
     19 #include "base/metrics/sparse_histogram.h"
     20 #include "base/metrics/statistics_recorder.h"
     21 #include "base/numerics/safe_conversions.h"
     22 #include "base/pickle.h"
     23 #include "base/process/process_handle.h"
     24 #include "base/rand_util.h"
     25 #include "base/strings/stringprintf.h"
     26 #include "base/synchronization/lock.h"
     27 #include "base/values.h"
     28 
     29 namespace base {
     30 
     31 std::string HistogramTypeToString(HistogramType type) {
     32   switch (type) {
     33     case HISTOGRAM:
     34       return "HISTOGRAM";
     35     case LINEAR_HISTOGRAM:
     36       return "LINEAR_HISTOGRAM";
     37     case BOOLEAN_HISTOGRAM:
     38       return "BOOLEAN_HISTOGRAM";
     39     case CUSTOM_HISTOGRAM:
     40       return "CUSTOM_HISTOGRAM";
     41     case SPARSE_HISTOGRAM:
     42       return "SPARSE_HISTOGRAM";
     43     case DUMMY_HISTOGRAM:
     44       return "DUMMY_HISTOGRAM";
     45   }
     46   NOTREACHED();
     47   return "UNKNOWN";
     48 }
     49 
     50 HistogramBase* DeserializeHistogramInfo(PickleIterator* iter) {
     51   int type;
     52   if (!iter->ReadInt(&type))
     53     return nullptr;
     54 
     55   switch (type) {
     56     case HISTOGRAM:
     57       return Histogram::DeserializeInfoImpl(iter);
     58     case LINEAR_HISTOGRAM:
     59       return LinearHistogram::DeserializeInfoImpl(iter);
     60     case BOOLEAN_HISTOGRAM:
     61       return BooleanHistogram::DeserializeInfoImpl(iter);
     62     case CUSTOM_HISTOGRAM:
     63       return CustomHistogram::DeserializeInfoImpl(iter);
     64     case SPARSE_HISTOGRAM:
     65       return SparseHistogram::DeserializeInfoImpl(iter);
     66     default:
     67       return nullptr;
     68   }
     69 }
     70 
     71 const HistogramBase::Sample HistogramBase::kSampleType_MAX = INT_MAX;
     72 
     73 HistogramBase::HistogramBase(const char* name)
     74     : histogram_name_(name), flags_(kNoFlags) {}
     75 
     76 HistogramBase::~HistogramBase() = default;
     77 
     78 void HistogramBase::CheckName(const StringPiece& name) const {
     79   DCHECK_EQ(StringPiece(histogram_name()), name);
     80 }
     81 
     82 void HistogramBase::SetFlags(int32_t flags) {
     83   HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
     84   subtle::NoBarrier_Store(&flags_, old_flags | flags);
     85 }
     86 
     87 void HistogramBase::ClearFlags(int32_t flags) {
     88   HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
     89   subtle::NoBarrier_Store(&flags_, old_flags & ~flags);
     90 }
     91 
     92 void HistogramBase::AddScaled(Sample value, int count, int scale) {
     93   DCHECK_LT(0, scale);
     94 
     95   // Convert raw count and probabilistically round up/down if the remainder
     96   // is more than a random number [0, scale). This gives a more accurate
     97   // count when there are a large number of records. RandInt is "inclusive",
     98   // hence the -1 for the max value.
     99   int64_t count_scaled = count / scale;
    100   if (count - (count_scaled * scale) > base::RandInt(0, scale - 1))
    101     count_scaled += 1;
    102   if (count_scaled == 0)
    103     return;
    104 
    105   AddCount(value, count_scaled);
    106 }
    107 
    108 void HistogramBase::AddKilo(Sample value, int count) {
    109   AddScaled(value, count, 1000);
    110 }
    111 
    112 void HistogramBase::AddKiB(Sample value, int count) {
    113   AddScaled(value, count, 1024);
    114 }
    115 
    116 void HistogramBase::AddTimeMillisecondsGranularity(const TimeDelta& time) {
    117   Add(saturated_cast<Sample>(time.InMilliseconds()));
    118 }
    119 
    120 void HistogramBase::AddTimeMicrosecondsGranularity(const TimeDelta& time) {
    121   // Intentionally drop high-resolution reports on clients with low-resolution
    122   // clocks. High-resolution metrics cannot make use of low-resolution data and
    123   // reporting it merely adds noise to the metric. https://crbug.com/807615#c16
    124   if (TimeTicks::IsHighResolution())
    125     Add(saturated_cast<Sample>(time.InMicroseconds()));
    126 }
    127 
    128 void HistogramBase::AddBoolean(bool value) {
    129   Add(value ? 1 : 0);
    130 }
    131 
    132 void HistogramBase::SerializeInfo(Pickle* pickle) const {
    133   pickle->WriteInt(GetHistogramType());
    134   SerializeInfoImpl(pickle);
    135 }
    136 
    137 uint32_t HistogramBase::FindCorruption(const HistogramSamples& samples) const {
    138   // Not supported by default.
    139   return NO_INCONSISTENCIES;
    140 }
    141 
    142 void HistogramBase::ValidateHistogramContents() const {}
    143 
    144 void HistogramBase::WriteJSON(std::string* output,
    145                               JSONVerbosityLevel verbosity_level) const {
    146   Count count;
    147   int64_t sum;
    148   std::unique_ptr<ListValue> buckets(new ListValue());
    149   GetCountAndBucketData(&count, &sum, buckets.get());
    150   std::unique_ptr<DictionaryValue> parameters(new DictionaryValue());
    151   GetParameters(parameters.get());
    152 
    153   JSONStringValueSerializer serializer(output);
    154   DictionaryValue root;
    155   root.SetString("name", histogram_name());
    156   root.SetInteger("count", count);
    157   root.SetDouble("sum", static_cast<double>(sum));
    158   root.SetInteger("flags", flags());
    159   root.Set("params", std::move(parameters));
    160   if (verbosity_level != JSON_VERBOSITY_LEVEL_OMIT_BUCKETS)
    161     root.Set("buckets", std::move(buckets));
    162   root.SetInteger("pid", GetUniqueIdForProcess());
    163   serializer.Serialize(root);
    164 }
    165 
    166 void HistogramBase::FindAndRunCallback(HistogramBase::Sample sample) const {
    167   if ((flags() & kCallbackExists) == 0)
    168     return;
    169 
    170   StatisticsRecorder::OnSampleCallback cb =
    171       StatisticsRecorder::FindCallback(histogram_name());
    172   if (!cb.is_null())
    173     cb.Run(sample);
    174 }
    175 
    176 void HistogramBase::WriteAsciiBucketGraph(double current_size,
    177                                           double max_size,
    178                                           std::string* output) const {
    179   const int k_line_length = 72;  // Maximal horizontal width of graph.
    180   int x_count = static_cast<int>(k_line_length * (current_size / max_size)
    181                                  + 0.5);
    182   int x_remainder = k_line_length - x_count;
    183 
    184   while (0 < x_count--)
    185     output->append("-");
    186   output->append("O");
    187   while (0 < x_remainder--)
    188     output->append(" ");
    189 }
    190 
    191 const std::string HistogramBase::GetSimpleAsciiBucketRange(
    192     Sample sample) const {
    193   return StringPrintf("%d", sample);
    194 }
    195 
    196 void HistogramBase::WriteAsciiBucketValue(Count current,
    197                                           double scaled_sum,
    198                                           std::string* output) const {
    199   StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
    200 }
    201 
    202 // static
    203 char const* HistogramBase::GetPermanentName(const std::string& name) {
    204   // A set of histogram names that provides the "permanent" lifetime required
    205   // by histogram objects for those strings that are not already code constants
    206   // or held in persistent memory.
    207   static LazyInstance<std::set<std::string>>::Leaky permanent_names;
    208   static LazyInstance<Lock>::Leaky permanent_names_lock;
    209 
    210   AutoLock lock(permanent_names_lock.Get());
    211   auto result = permanent_names.Get().insert(name);
    212   return result.first->c_str();
    213 }
    214 
    215 }  // namespace base
    216