xref: /aosp_15_r20/external/cronet/base/metrics/sparse_histogram.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/sparse_histogram.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <utility>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/metrics/dummy_histogram.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/metrics/metrics_hashes.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/metrics/persistent_histogram_allocator.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/metrics/persistent_sample_map.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/metrics/sample_map.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/metrics/statistics_recorder.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/pickle.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker namespace base {
24*6777b538SAndroid Build Coastguard Worker 
25*6777b538SAndroid Build Coastguard Worker typedef HistogramBase::Count Count;
26*6777b538SAndroid Build Coastguard Worker typedef HistogramBase::Sample Sample;
27*6777b538SAndroid Build Coastguard Worker 
28*6777b538SAndroid Build Coastguard Worker // static
FactoryGet(const std::string & name,int32_t flags)29*6777b538SAndroid Build Coastguard Worker HistogramBase* SparseHistogram::FactoryGet(const std::string& name,
30*6777b538SAndroid Build Coastguard Worker                                            int32_t flags) {
31*6777b538SAndroid Build Coastguard Worker   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
32*6777b538SAndroid Build Coastguard Worker   if (!histogram) {
33*6777b538SAndroid Build Coastguard Worker     // TODO(gayane): |HashMetricName| is called again in Histogram constructor.
34*6777b538SAndroid Build Coastguard Worker     // Refactor code to avoid the additional call.
35*6777b538SAndroid Build Coastguard Worker     bool should_record =
36*6777b538SAndroid Build Coastguard Worker         StatisticsRecorder::ShouldRecordHistogram(HashMetricNameAs32Bits(name));
37*6777b538SAndroid Build Coastguard Worker     if (!should_record)
38*6777b538SAndroid Build Coastguard Worker       return DummyHistogram::GetInstance();
39*6777b538SAndroid Build Coastguard Worker     // Try to create the histogram using a "persistent" allocator. As of
40*6777b538SAndroid Build Coastguard Worker     // 2016-02-25, the availability of such is controlled by a base::Feature
41*6777b538SAndroid Build Coastguard Worker     // that is off by default. If the allocator doesn't exist or if
42*6777b538SAndroid Build Coastguard Worker     // allocating from it fails, code below will allocate the histogram from
43*6777b538SAndroid Build Coastguard Worker     // the process heap.
44*6777b538SAndroid Build Coastguard Worker     PersistentMemoryAllocator::Reference histogram_ref = 0;
45*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<HistogramBase> tentative_histogram;
46*6777b538SAndroid Build Coastguard Worker     PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
47*6777b538SAndroid Build Coastguard Worker     if (allocator) {
48*6777b538SAndroid Build Coastguard Worker       tentative_histogram = allocator->AllocateHistogram(
49*6777b538SAndroid Build Coastguard Worker           SPARSE_HISTOGRAM, name, 0, 0, nullptr, flags, &histogram_ref);
50*6777b538SAndroid Build Coastguard Worker     }
51*6777b538SAndroid Build Coastguard Worker 
52*6777b538SAndroid Build Coastguard Worker     // Handle the case where no persistent allocator is present or the
53*6777b538SAndroid Build Coastguard Worker     // persistent allocation fails (perhaps because it is full).
54*6777b538SAndroid Build Coastguard Worker     if (!tentative_histogram) {
55*6777b538SAndroid Build Coastguard Worker       DCHECK(!histogram_ref);  // Should never have been set.
56*6777b538SAndroid Build Coastguard Worker       flags &= ~HistogramBase::kIsPersistent;
57*6777b538SAndroid Build Coastguard Worker       tentative_histogram.reset(new SparseHistogram(GetPermanentName(name)));
58*6777b538SAndroid Build Coastguard Worker       tentative_histogram->SetFlags(flags);
59*6777b538SAndroid Build Coastguard Worker     }
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker     // Register this histogram with the StatisticsRecorder. Keep a copy of
62*6777b538SAndroid Build Coastguard Worker     // the pointer value to tell later whether the locally created histogram
63*6777b538SAndroid Build Coastguard Worker     // was registered or deleted. The type is "void" because it could point
64*6777b538SAndroid Build Coastguard Worker     // to released memory after the following line.
65*6777b538SAndroid Build Coastguard Worker     const void* tentative_histogram_ptr = tentative_histogram.get();
66*6777b538SAndroid Build Coastguard Worker     histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
67*6777b538SAndroid Build Coastguard Worker         tentative_histogram.release());
68*6777b538SAndroid Build Coastguard Worker 
69*6777b538SAndroid Build Coastguard Worker     // Persistent histograms need some follow-up processing.
70*6777b538SAndroid Build Coastguard Worker     if (histogram_ref) {
71*6777b538SAndroid Build Coastguard Worker       allocator->FinalizeHistogram(histogram_ref,
72*6777b538SAndroid Build Coastguard Worker                                    histogram == tentative_histogram_ptr);
73*6777b538SAndroid Build Coastguard Worker     }
74*6777b538SAndroid Build Coastguard Worker   }
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType());
77*6777b538SAndroid Build Coastguard Worker   return histogram;
78*6777b538SAndroid Build Coastguard Worker }
79*6777b538SAndroid Build Coastguard Worker 
80*6777b538SAndroid Build Coastguard Worker // static
PersistentCreate(PersistentHistogramAllocator * allocator,const char * name,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)81*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HistogramBase> SparseHistogram::PersistentCreate(
82*6777b538SAndroid Build Coastguard Worker     PersistentHistogramAllocator* allocator,
83*6777b538SAndroid Build Coastguard Worker     const char* name,
84*6777b538SAndroid Build Coastguard Worker     HistogramSamples::Metadata* meta,
85*6777b538SAndroid Build Coastguard Worker     HistogramSamples::Metadata* logged_meta) {
86*6777b538SAndroid Build Coastguard Worker   return WrapUnique(new SparseHistogram(allocator, name, meta, logged_meta));
87*6777b538SAndroid Build Coastguard Worker }
88*6777b538SAndroid Build Coastguard Worker 
89*6777b538SAndroid Build Coastguard Worker SparseHistogram::~SparseHistogram() = default;
90*6777b538SAndroid Build Coastguard Worker 
name_hash() const91*6777b538SAndroid Build Coastguard Worker uint64_t SparseHistogram::name_hash() const {
92*6777b538SAndroid Build Coastguard Worker   return unlogged_samples_->id();
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker 
GetHistogramType() const95*6777b538SAndroid Build Coastguard Worker HistogramType SparseHistogram::GetHistogramType() const {
96*6777b538SAndroid Build Coastguard Worker   return SPARSE_HISTOGRAM;
97*6777b538SAndroid Build Coastguard Worker }
98*6777b538SAndroid Build Coastguard Worker 
HasConstructionArguments(Sample expected_minimum,Sample expected_maximum,size_t expected_bucket_count) const99*6777b538SAndroid Build Coastguard Worker bool SparseHistogram::HasConstructionArguments(
100*6777b538SAndroid Build Coastguard Worker     Sample expected_minimum,
101*6777b538SAndroid Build Coastguard Worker     Sample expected_maximum,
102*6777b538SAndroid Build Coastguard Worker     size_t expected_bucket_count) const {
103*6777b538SAndroid Build Coastguard Worker   // SparseHistogram never has min/max/bucket_count limit.
104*6777b538SAndroid Build Coastguard Worker   return false;
105*6777b538SAndroid Build Coastguard Worker }
106*6777b538SAndroid Build Coastguard Worker 
Add(Sample value)107*6777b538SAndroid Build Coastguard Worker void SparseHistogram::Add(Sample value) {
108*6777b538SAndroid Build Coastguard Worker   AddCount(value, 1);
109*6777b538SAndroid Build Coastguard Worker }
110*6777b538SAndroid Build Coastguard Worker 
AddCount(Sample value,int count)111*6777b538SAndroid Build Coastguard Worker void SparseHistogram::AddCount(Sample value, int count) {
112*6777b538SAndroid Build Coastguard Worker   if (count <= 0) {
113*6777b538SAndroid Build Coastguard Worker     NOTREACHED();
114*6777b538SAndroid Build Coastguard Worker     return;
115*6777b538SAndroid Build Coastguard Worker   }
116*6777b538SAndroid Build Coastguard Worker   {
117*6777b538SAndroid Build Coastguard Worker     base::AutoLock auto_lock(lock_);
118*6777b538SAndroid Build Coastguard Worker     unlogged_samples_->Accumulate(value, count);
119*6777b538SAndroid Build Coastguard Worker   }
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker   if (UNLIKELY(StatisticsRecorder::have_active_callbacks()))
122*6777b538SAndroid Build Coastguard Worker     FindAndRunCallbacks(value);
123*6777b538SAndroid Build Coastguard Worker }
124*6777b538SAndroid Build Coastguard Worker 
SnapshotSamples() const125*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
126*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
127*6777b538SAndroid Build Coastguard Worker 
128*6777b538SAndroid Build Coastguard Worker   base::AutoLock auto_lock(lock_);
129*6777b538SAndroid Build Coastguard Worker   snapshot->Add(*unlogged_samples_);
130*6777b538SAndroid Build Coastguard Worker   snapshot->Add(*logged_samples_);
131*6777b538SAndroid Build Coastguard Worker   return std::move(snapshot);
132*6777b538SAndroid Build Coastguard Worker }
133*6777b538SAndroid Build Coastguard Worker 
SnapshotUnloggedSamples() const134*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotUnloggedSamples()
135*6777b538SAndroid Build Coastguard Worker     const {
136*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker   base::AutoLock auto_lock(lock_);
139*6777b538SAndroid Build Coastguard Worker   snapshot->Add(*unlogged_samples_);
140*6777b538SAndroid Build Coastguard Worker 
141*6777b538SAndroid Build Coastguard Worker   return std::move(snapshot);
142*6777b538SAndroid Build Coastguard Worker }
143*6777b538SAndroid Build Coastguard Worker 
MarkSamplesAsLogged(const HistogramSamples & samples)144*6777b538SAndroid Build Coastguard Worker void SparseHistogram::MarkSamplesAsLogged(const HistogramSamples& samples) {
145*6777b538SAndroid Build Coastguard Worker   DCHECK(!final_delta_created_);
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker   base::AutoLock auto_lock(lock_);
148*6777b538SAndroid Build Coastguard Worker   unlogged_samples_->Subtract(samples);
149*6777b538SAndroid Build Coastguard Worker   logged_samples_->Add(samples);
150*6777b538SAndroid Build Coastguard Worker }
151*6777b538SAndroid Build Coastguard Worker 
SnapshotDelta()152*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotDelta() {
153*6777b538SAndroid Build Coastguard Worker   DCHECK(!final_delta_created_);
154*6777b538SAndroid Build Coastguard Worker 
155*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<SampleMap> snapshot =
156*6777b538SAndroid Build Coastguard Worker       std::make_unique<SampleMap>(name_hash());
157*6777b538SAndroid Build Coastguard Worker   base::AutoLock auto_lock(lock_);
158*6777b538SAndroid Build Coastguard Worker   snapshot->Extract(*unlogged_samples_);
159*6777b538SAndroid Build Coastguard Worker   logged_samples_->Add(*snapshot);
160*6777b538SAndroid Build Coastguard Worker   return std::move(snapshot);
161*6777b538SAndroid Build Coastguard Worker }
162*6777b538SAndroid Build Coastguard Worker 
SnapshotFinalDelta() const163*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotFinalDelta() const {
164*6777b538SAndroid Build Coastguard Worker   DCHECK(!final_delta_created_);
165*6777b538SAndroid Build Coastguard Worker   final_delta_created_ = true;
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
168*6777b538SAndroid Build Coastguard Worker   base::AutoLock auto_lock(lock_);
169*6777b538SAndroid Build Coastguard Worker   snapshot->Add(*unlogged_samples_);
170*6777b538SAndroid Build Coastguard Worker 
171*6777b538SAndroid Build Coastguard Worker   return std::move(snapshot);
172*6777b538SAndroid Build Coastguard Worker }
173*6777b538SAndroid Build Coastguard Worker 
AddSamples(const HistogramSamples & samples)174*6777b538SAndroid Build Coastguard Worker void SparseHistogram::AddSamples(const HistogramSamples& samples) {
175*6777b538SAndroid Build Coastguard Worker   base::AutoLock auto_lock(lock_);
176*6777b538SAndroid Build Coastguard Worker   unlogged_samples_->Add(samples);
177*6777b538SAndroid Build Coastguard Worker }
178*6777b538SAndroid Build Coastguard Worker 
AddSamplesFromPickle(PickleIterator * iter)179*6777b538SAndroid Build Coastguard Worker bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) {
180*6777b538SAndroid Build Coastguard Worker   base::AutoLock auto_lock(lock_);
181*6777b538SAndroid Build Coastguard Worker   return unlogged_samples_->AddFromPickle(iter);
182*6777b538SAndroid Build Coastguard Worker }
183*6777b538SAndroid Build Coastguard Worker 
ToGraphDict() const184*6777b538SAndroid Build Coastguard Worker base::Value::Dict SparseHistogram::ToGraphDict() const {
185*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<HistogramSamples> snapshot = SnapshotSamples();
186*6777b538SAndroid Build Coastguard Worker   return snapshot->ToGraphDict(histogram_name(), flags());
187*6777b538SAndroid Build Coastguard Worker }
188*6777b538SAndroid Build Coastguard Worker 
SerializeInfoImpl(Pickle * pickle) const189*6777b538SAndroid Build Coastguard Worker void SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
190*6777b538SAndroid Build Coastguard Worker   pickle->WriteString(histogram_name());
191*6777b538SAndroid Build Coastguard Worker   pickle->WriteInt(flags());
192*6777b538SAndroid Build Coastguard Worker }
193*6777b538SAndroid Build Coastguard Worker 
SparseHistogram(const char * name)194*6777b538SAndroid Build Coastguard Worker SparseHistogram::SparseHistogram(const char* name)
195*6777b538SAndroid Build Coastguard Worker     : HistogramBase(name),
196*6777b538SAndroid Build Coastguard Worker       unlogged_samples_(new SampleMap(HashMetricName(name))),
197*6777b538SAndroid Build Coastguard Worker       logged_samples_(new SampleMap(unlogged_samples_->id())) {}
198*6777b538SAndroid Build Coastguard Worker 
SparseHistogram(PersistentHistogramAllocator * allocator,const char * name,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)199*6777b538SAndroid Build Coastguard Worker SparseHistogram::SparseHistogram(PersistentHistogramAllocator* allocator,
200*6777b538SAndroid Build Coastguard Worker                                  const char* name,
201*6777b538SAndroid Build Coastguard Worker                                  HistogramSamples::Metadata* meta,
202*6777b538SAndroid Build Coastguard Worker                                  HistogramSamples::Metadata* logged_meta)
203*6777b538SAndroid Build Coastguard Worker     : HistogramBase(name),
204*6777b538SAndroid Build Coastguard Worker       // While other histogram types maintain a static vector of values with
205*6777b538SAndroid Build Coastguard Worker       // sufficient space for both "active" and "logged" samples, with each
206*6777b538SAndroid Build Coastguard Worker       // SampleVector being given the appropriate half, sparse histograms
207*6777b538SAndroid Build Coastguard Worker       // have no such initial allocation. Each sample has its own record
208*6777b538SAndroid Build Coastguard Worker       // attached to a single PersistentSampleMap by a common 64-bit identifier.
209*6777b538SAndroid Build Coastguard Worker       // Since a sparse histogram has two sample maps (active and logged),
210*6777b538SAndroid Build Coastguard Worker       // there must be two sets of sample records with diffent IDs. The
211*6777b538SAndroid Build Coastguard Worker       // "active" samples use, for convenience purposes, an ID matching
212*6777b538SAndroid Build Coastguard Worker       // that of the histogram while the "logged" samples use that number
213*6777b538SAndroid Build Coastguard Worker       // plus 1.
214*6777b538SAndroid Build Coastguard Worker       unlogged_samples_(
215*6777b538SAndroid Build Coastguard Worker           new PersistentSampleMap(HashMetricName(name), allocator, meta)),
216*6777b538SAndroid Build Coastguard Worker       logged_samples_(new PersistentSampleMap(unlogged_samples_->id() + 1,
217*6777b538SAndroid Build Coastguard Worker                                               allocator,
218*6777b538SAndroid Build Coastguard Worker                                               logged_meta)) {}
219*6777b538SAndroid Build Coastguard Worker 
DeserializeInfoImpl(PickleIterator * iter)220*6777b538SAndroid Build Coastguard Worker HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
221*6777b538SAndroid Build Coastguard Worker   std::string histogram_name;
222*6777b538SAndroid Build Coastguard Worker   int flags;
223*6777b538SAndroid Build Coastguard Worker   if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) {
224*6777b538SAndroid Build Coastguard Worker     DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
225*6777b538SAndroid Build Coastguard Worker     return nullptr;
226*6777b538SAndroid Build Coastguard Worker   }
227*6777b538SAndroid Build Coastguard Worker 
228*6777b538SAndroid Build Coastguard Worker   flags &= ~HistogramBase::kIPCSerializationSourceFlag;
229*6777b538SAndroid Build Coastguard Worker 
230*6777b538SAndroid Build Coastguard Worker   return SparseHistogram::FactoryGet(histogram_name, flags);
231*6777b538SAndroid Build Coastguard Worker }
232*6777b538SAndroid Build Coastguard Worker 
GetParameters() const233*6777b538SAndroid Build Coastguard Worker Value::Dict SparseHistogram::GetParameters() const {
234*6777b538SAndroid Build Coastguard Worker   // Unlike Histogram::GetParameters, only set the type here, and no other
235*6777b538SAndroid Build Coastguard Worker   // params. The other params do not make sense for sparse histograms.
236*6777b538SAndroid Build Coastguard Worker   Value::Dict params;
237*6777b538SAndroid Build Coastguard Worker   params.Set("type", HistogramTypeToString(GetHistogramType()));
238*6777b538SAndroid Build Coastguard Worker   return params;
239*6777b538SAndroid Build Coastguard Worker }
240*6777b538SAndroid Build Coastguard Worker 
241*6777b538SAndroid Build Coastguard Worker }  // namespace base
242