• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
HistogramTypeToString(HistogramType type)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 
DeserializeHistogramInfo(PickleIterator * iter)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 
HistogramBase(const char * name)73 HistogramBase::HistogramBase(const char* name)
74     : histogram_name_(name), flags_(kNoFlags) {}
75 
76 HistogramBase::~HistogramBase() = default;
77 
CheckName(const StringPiece & name) const78 void HistogramBase::CheckName(const StringPiece& name) const {
79   DCHECK_EQ(StringPiece(histogram_name()), name);
80 }
81 
SetFlags(int32_t flags)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 
ClearFlags(int32_t flags)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 
AddScaled(Sample value,int count,int scale)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 
AddKilo(Sample value,int count)108 void HistogramBase::AddKilo(Sample value, int count) {
109   AddScaled(value, count, 1000);
110 }
111 
AddKiB(Sample value,int count)112 void HistogramBase::AddKiB(Sample value, int count) {
113   AddScaled(value, count, 1024);
114 }
115 
AddTimeMillisecondsGranularity(const TimeDelta & time)116 void HistogramBase::AddTimeMillisecondsGranularity(const TimeDelta& time) {
117   Add(saturated_cast<Sample>(time.InMilliseconds()));
118 }
119 
AddTimeMicrosecondsGranularity(const TimeDelta & time)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 
AddBoolean(bool value)128 void HistogramBase::AddBoolean(bool value) {
129   Add(value ? 1 : 0);
130 }
131 
SerializeInfo(Pickle * pickle) const132 void HistogramBase::SerializeInfo(Pickle* pickle) const {
133   pickle->WriteInt(GetHistogramType());
134   SerializeInfoImpl(pickle);
135 }
136 
FindCorruption(const HistogramSamples & samples) const137 uint32_t HistogramBase::FindCorruption(const HistogramSamples& samples) const {
138   // Not supported by default.
139   return NO_INCONSISTENCIES;
140 }
141 
ValidateHistogramContents() const142 void HistogramBase::ValidateHistogramContents() const {}
143 
WriteJSON(std::string * output,JSONVerbosityLevel verbosity_level) const144 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 
FindAndRunCallback(HistogramBase::Sample sample) const166 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 
WriteAsciiBucketGraph(double current_size,double max_size,std::string * output) const176 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 
GetSimpleAsciiBucketRange(Sample sample) const191 const std::string HistogramBase::GetSimpleAsciiBucketRange(
192     Sample sample) const {
193   return StringPrintf("%d", sample);
194 }
195 
WriteAsciiBucketValue(Count current,double scaled_sum,std::string * output) const196 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
GetPermanentName(const std::string & name)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