xref: /aosp_15_r20/external/cronet/base/metrics/histogram_base.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_base.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <limits.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include <memory>
10*6777b538SAndroid Build Coastguard Worker #include <set>
11*6777b538SAndroid Build Coastguard Worker #include <string_view>
12*6777b538SAndroid Build Coastguard Worker #include <utility>
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/json/json_string_value_serializer.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_samples.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/metrics/sparse_histogram.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/metrics/statistics_recorder.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/no_destructor.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/pickle.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/process/process_handle.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker namespace base {
32*6777b538SAndroid Build Coastguard Worker 
HistogramTypeToString(HistogramType type)33*6777b538SAndroid Build Coastguard Worker std::string HistogramTypeToString(HistogramType type) {
34*6777b538SAndroid Build Coastguard Worker   switch (type) {
35*6777b538SAndroid Build Coastguard Worker     case HISTOGRAM:
36*6777b538SAndroid Build Coastguard Worker       return "HISTOGRAM";
37*6777b538SAndroid Build Coastguard Worker     case LINEAR_HISTOGRAM:
38*6777b538SAndroid Build Coastguard Worker       return "LINEAR_HISTOGRAM";
39*6777b538SAndroid Build Coastguard Worker     case BOOLEAN_HISTOGRAM:
40*6777b538SAndroid Build Coastguard Worker       return "BOOLEAN_HISTOGRAM";
41*6777b538SAndroid Build Coastguard Worker     case CUSTOM_HISTOGRAM:
42*6777b538SAndroid Build Coastguard Worker       return "CUSTOM_HISTOGRAM";
43*6777b538SAndroid Build Coastguard Worker     case SPARSE_HISTOGRAM:
44*6777b538SAndroid Build Coastguard Worker       return "SPARSE_HISTOGRAM";
45*6777b538SAndroid Build Coastguard Worker     case DUMMY_HISTOGRAM:
46*6777b538SAndroid Build Coastguard Worker       return "DUMMY_HISTOGRAM";
47*6777b538SAndroid Build Coastguard Worker   }
48*6777b538SAndroid Build Coastguard Worker   NOTREACHED();
49*6777b538SAndroid Build Coastguard Worker   return "UNKNOWN";
50*6777b538SAndroid Build Coastguard Worker }
51*6777b538SAndroid Build Coastguard Worker 
DeserializeHistogramInfo(PickleIterator * iter)52*6777b538SAndroid Build Coastguard Worker HistogramBase* DeserializeHistogramInfo(PickleIterator* iter) {
53*6777b538SAndroid Build Coastguard Worker   int type;
54*6777b538SAndroid Build Coastguard Worker   if (!iter->ReadInt(&type))
55*6777b538SAndroid Build Coastguard Worker     return nullptr;
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker   switch (type) {
58*6777b538SAndroid Build Coastguard Worker     case HISTOGRAM:
59*6777b538SAndroid Build Coastguard Worker       return Histogram::DeserializeInfoImpl(iter);
60*6777b538SAndroid Build Coastguard Worker     case LINEAR_HISTOGRAM:
61*6777b538SAndroid Build Coastguard Worker       return LinearHistogram::DeserializeInfoImpl(iter);
62*6777b538SAndroid Build Coastguard Worker     case BOOLEAN_HISTOGRAM:
63*6777b538SAndroid Build Coastguard Worker       return BooleanHistogram::DeserializeInfoImpl(iter);
64*6777b538SAndroid Build Coastguard Worker     case CUSTOM_HISTOGRAM:
65*6777b538SAndroid Build Coastguard Worker       return CustomHistogram::DeserializeInfoImpl(iter);
66*6777b538SAndroid Build Coastguard Worker     case SPARSE_HISTOGRAM:
67*6777b538SAndroid Build Coastguard Worker       return SparseHistogram::DeserializeInfoImpl(iter);
68*6777b538SAndroid Build Coastguard Worker     default:
69*6777b538SAndroid Build Coastguard Worker       return nullptr;
70*6777b538SAndroid Build Coastguard Worker   }
71*6777b538SAndroid Build Coastguard Worker }
72*6777b538SAndroid Build Coastguard Worker 
CountAndBucketData(Count count,int64_t sum,Value::List buckets)73*6777b538SAndroid Build Coastguard Worker HistogramBase::CountAndBucketData::CountAndBucketData(Count count,
74*6777b538SAndroid Build Coastguard Worker                                                       int64_t sum,
75*6777b538SAndroid Build Coastguard Worker                                                       Value::List buckets)
76*6777b538SAndroid Build Coastguard Worker     : count(count), sum(sum), buckets(std::move(buckets)) {}
77*6777b538SAndroid Build Coastguard Worker 
78*6777b538SAndroid Build Coastguard Worker HistogramBase::CountAndBucketData::~CountAndBucketData() = default;
79*6777b538SAndroid Build Coastguard Worker 
80*6777b538SAndroid Build Coastguard Worker HistogramBase::CountAndBucketData::CountAndBucketData(
81*6777b538SAndroid Build Coastguard Worker     CountAndBucketData&& other) = default;
82*6777b538SAndroid Build Coastguard Worker 
83*6777b538SAndroid Build Coastguard Worker HistogramBase::CountAndBucketData& HistogramBase::CountAndBucketData::operator=(
84*6777b538SAndroid Build Coastguard Worker     CountAndBucketData&& other) = default;
85*6777b538SAndroid Build Coastguard Worker 
86*6777b538SAndroid Build Coastguard Worker const HistogramBase::Sample HistogramBase::kSampleType_MAX = INT_MAX;
87*6777b538SAndroid Build Coastguard Worker 
HistogramBase(const char * name)88*6777b538SAndroid Build Coastguard Worker HistogramBase::HistogramBase(const char* name)
89*6777b538SAndroid Build Coastguard Worker     : histogram_name_(name), flags_(kNoFlags) {}
90*6777b538SAndroid Build Coastguard Worker 
91*6777b538SAndroid Build Coastguard Worker HistogramBase::~HistogramBase() = default;
92*6777b538SAndroid Build Coastguard Worker 
CheckName(std::string_view name) const93*6777b538SAndroid Build Coastguard Worker void HistogramBase::CheckName(std::string_view name) const {
94*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(std::string_view(histogram_name()), name)
95*6777b538SAndroid Build Coastguard Worker       << "Provided histogram name doesn't match instance name. Are you using a "
96*6777b538SAndroid Build Coastguard Worker          "dynamic string in a macro?";
97*6777b538SAndroid Build Coastguard Worker }
98*6777b538SAndroid Build Coastguard Worker 
SetFlags(int32_t flags)99*6777b538SAndroid Build Coastguard Worker void HistogramBase::SetFlags(int32_t flags) {
100*6777b538SAndroid Build Coastguard Worker   flags_.fetch_or(flags, std::memory_order_relaxed);
101*6777b538SAndroid Build Coastguard Worker }
102*6777b538SAndroid Build Coastguard Worker 
ClearFlags(int32_t flags)103*6777b538SAndroid Build Coastguard Worker void HistogramBase::ClearFlags(int32_t flags) {
104*6777b538SAndroid Build Coastguard Worker   flags_.fetch_and(~flags, std::memory_order_relaxed);
105*6777b538SAndroid Build Coastguard Worker }
106*6777b538SAndroid Build Coastguard Worker 
HasFlags(int32_t flags) const107*6777b538SAndroid Build Coastguard Worker bool HistogramBase::HasFlags(int32_t flags) const {
108*6777b538SAndroid Build Coastguard Worker   // Check this->flags() is a superset of |flags|, i.e. every flag in |flags| is
109*6777b538SAndroid Build Coastguard Worker   // included.
110*6777b538SAndroid Build Coastguard Worker   return (this->flags() & flags) == flags;
111*6777b538SAndroid Build Coastguard Worker }
112*6777b538SAndroid Build Coastguard Worker 
AddScaled(Sample value,int count,int scale)113*6777b538SAndroid Build Coastguard Worker void HistogramBase::AddScaled(Sample value, int count, int scale) {
114*6777b538SAndroid Build Coastguard Worker   DCHECK_GT(scale, 0);
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker   // Convert raw count and probabilistically round up/down if the remainder
117*6777b538SAndroid Build Coastguard Worker   // is more than a random number [0, scale). This gives a more accurate
118*6777b538SAndroid Build Coastguard Worker   // count when there are a large number of records. RandInt is "inclusive",
119*6777b538SAndroid Build Coastguard Worker   // hence the -1 for the max value.
120*6777b538SAndroid Build Coastguard Worker   int count_scaled = count / scale;
121*6777b538SAndroid Build Coastguard Worker   if (count - (count_scaled * scale) > base::RandInt(0, scale - 1))
122*6777b538SAndroid Build Coastguard Worker     ++count_scaled;
123*6777b538SAndroid Build Coastguard Worker   if (count_scaled <= 0)
124*6777b538SAndroid Build Coastguard Worker     return;
125*6777b538SAndroid Build Coastguard Worker 
126*6777b538SAndroid Build Coastguard Worker   AddCount(value, count_scaled);
127*6777b538SAndroid Build Coastguard Worker }
128*6777b538SAndroid Build Coastguard Worker 
AddKilo(Sample value,int count)129*6777b538SAndroid Build Coastguard Worker void HistogramBase::AddKilo(Sample value, int count) {
130*6777b538SAndroid Build Coastguard Worker   AddScaled(value, count, 1000);
131*6777b538SAndroid Build Coastguard Worker }
132*6777b538SAndroid Build Coastguard Worker 
AddKiB(Sample value,int count)133*6777b538SAndroid Build Coastguard Worker void HistogramBase::AddKiB(Sample value, int count) {
134*6777b538SAndroid Build Coastguard Worker   AddScaled(value, count, 1024);
135*6777b538SAndroid Build Coastguard Worker }
136*6777b538SAndroid Build Coastguard Worker 
AddTimeMillisecondsGranularity(const TimeDelta & time)137*6777b538SAndroid Build Coastguard Worker void HistogramBase::AddTimeMillisecondsGranularity(const TimeDelta& time) {
138*6777b538SAndroid Build Coastguard Worker   Add(saturated_cast<Sample>(time.InMilliseconds()));
139*6777b538SAndroid Build Coastguard Worker }
140*6777b538SAndroid Build Coastguard Worker 
AddTimeMicrosecondsGranularity(const TimeDelta & time)141*6777b538SAndroid Build Coastguard Worker void HistogramBase::AddTimeMicrosecondsGranularity(const TimeDelta& time) {
142*6777b538SAndroid Build Coastguard Worker   // Intentionally drop high-resolution reports on clients with low-resolution
143*6777b538SAndroid Build Coastguard Worker   // clocks. High-resolution metrics cannot make use of low-resolution data and
144*6777b538SAndroid Build Coastguard Worker   // reporting it merely adds noise to the metric. https://crbug.com/807615#c16
145*6777b538SAndroid Build Coastguard Worker   if (TimeTicks::IsHighResolution())
146*6777b538SAndroid Build Coastguard Worker     Add(saturated_cast<Sample>(time.InMicroseconds()));
147*6777b538SAndroid Build Coastguard Worker }
148*6777b538SAndroid Build Coastguard Worker 
AddBoolean(bool value)149*6777b538SAndroid Build Coastguard Worker void HistogramBase::AddBoolean(bool value) {
150*6777b538SAndroid Build Coastguard Worker   Add(value ? 1 : 0);
151*6777b538SAndroid Build Coastguard Worker }
152*6777b538SAndroid Build Coastguard Worker 
SerializeInfo(Pickle * pickle) const153*6777b538SAndroid Build Coastguard Worker void HistogramBase::SerializeInfo(Pickle* pickle) const {
154*6777b538SAndroid Build Coastguard Worker   pickle->WriteInt(GetHistogramType());
155*6777b538SAndroid Build Coastguard Worker   SerializeInfoImpl(pickle);
156*6777b538SAndroid Build Coastguard Worker }
157*6777b538SAndroid Build Coastguard Worker 
FindCorruption(const HistogramSamples & samples) const158*6777b538SAndroid Build Coastguard Worker uint32_t HistogramBase::FindCorruption(const HistogramSamples& samples) const {
159*6777b538SAndroid Build Coastguard Worker   // Not supported by default.
160*6777b538SAndroid Build Coastguard Worker   return NO_INCONSISTENCIES;
161*6777b538SAndroid Build Coastguard Worker }
162*6777b538SAndroid Build Coastguard Worker 
WriteJSON(std::string * output,JSONVerbosityLevel verbosity_level) const163*6777b538SAndroid Build Coastguard Worker void HistogramBase::WriteJSON(std::string* output,
164*6777b538SAndroid Build Coastguard Worker                               JSONVerbosityLevel verbosity_level) const {
165*6777b538SAndroid Build Coastguard Worker   CountAndBucketData count_and_bucket_data = GetCountAndBucketData();
166*6777b538SAndroid Build Coastguard Worker   Value::Dict parameters = GetParameters();
167*6777b538SAndroid Build Coastguard Worker 
168*6777b538SAndroid Build Coastguard Worker   JSONStringValueSerializer serializer(output);
169*6777b538SAndroid Build Coastguard Worker   Value::Dict root;
170*6777b538SAndroid Build Coastguard Worker   root.Set("name", histogram_name());
171*6777b538SAndroid Build Coastguard Worker   root.Set("count", count_and_bucket_data.count);
172*6777b538SAndroid Build Coastguard Worker   root.Set("sum", static_cast<double>(count_and_bucket_data.sum));
173*6777b538SAndroid Build Coastguard Worker   root.Set("flags", flags());
174*6777b538SAndroid Build Coastguard Worker   root.Set("params", std::move(parameters));
175*6777b538SAndroid Build Coastguard Worker   if (verbosity_level != JSON_VERBOSITY_LEVEL_OMIT_BUCKETS)
176*6777b538SAndroid Build Coastguard Worker     root.Set("buckets", std::move(count_and_bucket_data.buckets));
177*6777b538SAndroid Build Coastguard Worker   root.Set("pid", static_cast<int>(GetUniqueIdForProcess().GetUnsafeValue()));
178*6777b538SAndroid Build Coastguard Worker   serializer.Serialize(root);
179*6777b538SAndroid Build Coastguard Worker }
180*6777b538SAndroid Build Coastguard Worker 
FindAndRunCallbacks(HistogramBase::Sample sample) const181*6777b538SAndroid Build Coastguard Worker void HistogramBase::FindAndRunCallbacks(HistogramBase::Sample sample) const {
182*6777b538SAndroid Build Coastguard Worker   StatisticsRecorder::GlobalSampleCallback global_sample_callback =
183*6777b538SAndroid Build Coastguard Worker       StatisticsRecorder::global_sample_callback();
184*6777b538SAndroid Build Coastguard Worker   if (global_sample_callback)
185*6777b538SAndroid Build Coastguard Worker     global_sample_callback(histogram_name(), name_hash(), sample);
186*6777b538SAndroid Build Coastguard Worker 
187*6777b538SAndroid Build Coastguard Worker   // We check the flag first since it is very cheap and we can avoid the
188*6777b538SAndroid Build Coastguard Worker   // function call and lock overhead of FindAndRunHistogramCallbacks().
189*6777b538SAndroid Build Coastguard Worker   if (!HasFlags(kCallbackExists)) {
190*6777b538SAndroid Build Coastguard Worker     return;
191*6777b538SAndroid Build Coastguard Worker   }
192*6777b538SAndroid Build Coastguard Worker 
193*6777b538SAndroid Build Coastguard Worker   StatisticsRecorder::FindAndRunHistogramCallbacks(
194*6777b538SAndroid Build Coastguard Worker       base::PassKey<HistogramBase>(), histogram_name(), name_hash(), sample);
195*6777b538SAndroid Build Coastguard Worker }
196*6777b538SAndroid Build Coastguard Worker 
GetCountAndBucketData() const197*6777b538SAndroid Build Coastguard Worker HistogramBase::CountAndBucketData HistogramBase::GetCountAndBucketData() const {
198*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<HistogramSamples> snapshot = SnapshotSamples();
199*6777b538SAndroid Build Coastguard Worker   Count count = snapshot->TotalCount();
200*6777b538SAndroid Build Coastguard Worker   int64_t sum = snapshot->sum();
201*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<SampleCountIterator> it = snapshot->Iterator();
202*6777b538SAndroid Build Coastguard Worker 
203*6777b538SAndroid Build Coastguard Worker   Value::List buckets;
204*6777b538SAndroid Build Coastguard Worker   while (!it->Done()) {
205*6777b538SAndroid Build Coastguard Worker     Sample bucket_min;
206*6777b538SAndroid Build Coastguard Worker     int64_t bucket_max;
207*6777b538SAndroid Build Coastguard Worker     Count bucket_count;
208*6777b538SAndroid Build Coastguard Worker     it->Get(&bucket_min, &bucket_max, &bucket_count);
209*6777b538SAndroid Build Coastguard Worker 
210*6777b538SAndroid Build Coastguard Worker     Value::Dict bucket_value;
211*6777b538SAndroid Build Coastguard Worker     bucket_value.Set("low", bucket_min);
212*6777b538SAndroid Build Coastguard Worker     // TODO(crbug.com/1334256): Make base::Value able to hold int64_t and remove
213*6777b538SAndroid Build Coastguard Worker     // this cast.
214*6777b538SAndroid Build Coastguard Worker     bucket_value.Set("high", static_cast<int>(bucket_max));
215*6777b538SAndroid Build Coastguard Worker     bucket_value.Set("count", bucket_count);
216*6777b538SAndroid Build Coastguard Worker     buckets.Append(std::move(bucket_value));
217*6777b538SAndroid Build Coastguard Worker     it->Next();
218*6777b538SAndroid Build Coastguard Worker   }
219*6777b538SAndroid Build Coastguard Worker 
220*6777b538SAndroid Build Coastguard Worker   return CountAndBucketData(count, sum, std::move(buckets));
221*6777b538SAndroid Build Coastguard Worker }
222*6777b538SAndroid Build Coastguard Worker 
WriteAsciiBucketGraph(double x_count,int line_length,std::string * output) const223*6777b538SAndroid Build Coastguard Worker void HistogramBase::WriteAsciiBucketGraph(double x_count,
224*6777b538SAndroid Build Coastguard Worker                                           int line_length,
225*6777b538SAndroid Build Coastguard Worker                                           std::string* output) const {
226*6777b538SAndroid Build Coastguard Worker   int x_remainder = line_length - x_count;
227*6777b538SAndroid Build Coastguard Worker 
228*6777b538SAndroid Build Coastguard Worker   while (0 < x_count--)
229*6777b538SAndroid Build Coastguard Worker     output->append("-");
230*6777b538SAndroid Build Coastguard Worker   output->append("O");
231*6777b538SAndroid Build Coastguard Worker   while (0 < x_remainder--)
232*6777b538SAndroid Build Coastguard Worker     output->append(" ");
233*6777b538SAndroid Build Coastguard Worker }
234*6777b538SAndroid Build Coastguard Worker 
GetSimpleAsciiBucketRange(Sample sample) const235*6777b538SAndroid Build Coastguard Worker const std::string HistogramBase::GetSimpleAsciiBucketRange(
236*6777b538SAndroid Build Coastguard Worker     Sample sample) const {
237*6777b538SAndroid Build Coastguard Worker   return StringPrintf("%d", sample);
238*6777b538SAndroid Build Coastguard Worker }
239*6777b538SAndroid Build Coastguard Worker 
WriteAsciiBucketValue(Count current,double scaled_sum,std::string * output) const240*6777b538SAndroid Build Coastguard Worker void HistogramBase::WriteAsciiBucketValue(Count current,
241*6777b538SAndroid Build Coastguard Worker                                           double scaled_sum,
242*6777b538SAndroid Build Coastguard Worker                                           std::string* output) const {
243*6777b538SAndroid Build Coastguard Worker   StringAppendF(output, " (%d = %3.1f%%)", current, current / scaled_sum);
244*6777b538SAndroid Build Coastguard Worker }
245*6777b538SAndroid Build Coastguard Worker 
WriteAscii(std::string * output) const246*6777b538SAndroid Build Coastguard Worker void HistogramBase::WriteAscii(std::string* output) const {
247*6777b538SAndroid Build Coastguard Worker   base::Value::Dict graph_dict = ToGraphDict();
248*6777b538SAndroid Build Coastguard Worker   output->append(*graph_dict.FindString("header"));
249*6777b538SAndroid Build Coastguard Worker   output->append("\n");
250*6777b538SAndroid Build Coastguard Worker   output->append(*graph_dict.FindString("body"));
251*6777b538SAndroid Build Coastguard Worker }
252*6777b538SAndroid Build Coastguard Worker 
253*6777b538SAndroid Build Coastguard Worker // static
GetPermanentName(std::string_view name)254*6777b538SAndroid Build Coastguard Worker char const* HistogramBase::GetPermanentName(std::string_view name) {
255*6777b538SAndroid Build Coastguard Worker   // A set of histogram names that provides the "permanent" lifetime required
256*6777b538SAndroid Build Coastguard Worker   // by histogram objects for those strings that are not already code constants
257*6777b538SAndroid Build Coastguard Worker   // or held in persistent memory.
258*6777b538SAndroid Build Coastguard Worker   static base::NoDestructor<std::set<std::string>> permanent_names;
259*6777b538SAndroid Build Coastguard Worker   static base::NoDestructor<Lock> permanent_names_lock;
260*6777b538SAndroid Build Coastguard Worker 
261*6777b538SAndroid Build Coastguard Worker   AutoLock lock(*permanent_names_lock);
262*6777b538SAndroid Build Coastguard Worker   auto result = permanent_names->insert(std::string(name));
263*6777b538SAndroid Build Coastguard Worker   return result.first->c_str();
264*6777b538SAndroid Build Coastguard Worker }
265*6777b538SAndroid Build Coastguard Worker 
266*6777b538SAndroid Build Coastguard Worker }  // namespace base
267