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