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