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
HistogramTypeToString(HistogramType type)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
DeserializeHistogramInfo(PickleIterator * iter)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
HistogramBase(const std::string & name)66 HistogramBase::HistogramBase(const std::string& name)
67 : histogram_name_(name),
68 flags_(kNoFlags) {}
69
~HistogramBase()70 HistogramBase::~HistogramBase() {}
71
CheckName(const StringPiece & name) const72 void HistogramBase::CheckName(const StringPiece& name) const {
73 DCHECK_EQ(histogram_name(), name);
74 }
75
SetFlags(int32_t flags)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
ClearFlags(int32_t flags)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
AddTime(const TimeDelta & time)86 void HistogramBase::AddTime(const TimeDelta& time) {
87 Add(static_cast<Sample>(time.InMilliseconds()));
88 }
89
AddBoolean(bool value)90 void HistogramBase::AddBoolean(bool value) {
91 Add(value ? 1 : 0);
92 }
93
SerializeInfo(Pickle * pickle) const94 bool HistogramBase::SerializeInfo(Pickle* pickle) const {
95 if (!pickle->WriteInt(GetHistogramType()))
96 return false;
97 return SerializeInfoImpl(pickle);
98 }
99
FindCorruption(const HistogramSamples & samples) const100 uint32_t HistogramBase::FindCorruption(const HistogramSamples& samples) const {
101 // Not supported by default.
102 return NO_INCONSISTENCIES;
103 }
104
WriteJSON(std::string * output) const105 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
EnableActivityReportHistogram(const std::string & process_type)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
FindAndRunCallback(HistogramBase::Sample sample) const151 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
WriteAsciiBucketGraph(double current_size,double max_size,std::string * output) const161 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
GetSimpleAsciiBucketRange(Sample sample) const176 const std::string HistogramBase::GetSimpleAsciiBucketRange(
177 Sample sample) const {
178 return StringPrintf("%d", sample);
179 }
180
WriteAsciiBucketValue(Count current,double scaled_sum,std::string * output) const181 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
ReportHistogramActivity(const HistogramBase & histogram,ReportActivity activity)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