xref: /aosp_15_r20/external/libchrome/base/metrics/histogram_samples.h (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 #ifndef BASE_METRICS_HISTOGRAM_SAMPLES_H_
6*635a8641SAndroid Build Coastguard Worker #define BASE_METRICS_HISTOGRAM_SAMPLES_H_
7*635a8641SAndroid Build Coastguard Worker 
8*635a8641SAndroid Build Coastguard Worker #include <stddef.h>
9*635a8641SAndroid Build Coastguard Worker #include <stdint.h>
10*635a8641SAndroid Build Coastguard Worker 
11*635a8641SAndroid Build Coastguard Worker #include <limits>
12*635a8641SAndroid Build Coastguard Worker #include <memory>
13*635a8641SAndroid Build Coastguard Worker 
14*635a8641SAndroid Build Coastguard Worker #include "base/atomicops.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/macros.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/metrics/histogram_base.h"
17*635a8641SAndroid Build Coastguard Worker 
18*635a8641SAndroid Build Coastguard Worker namespace base {
19*635a8641SAndroid Build Coastguard Worker 
20*635a8641SAndroid Build Coastguard Worker class Pickle;
21*635a8641SAndroid Build Coastguard Worker class PickleIterator;
22*635a8641SAndroid Build Coastguard Worker class SampleCountIterator;
23*635a8641SAndroid Build Coastguard Worker 
24*635a8641SAndroid Build Coastguard Worker // HistogramSamples is a container storing all samples of a histogram. All
25*635a8641SAndroid Build Coastguard Worker // elements must be of a fixed width to ensure 32/64-bit interoperability.
26*635a8641SAndroid Build Coastguard Worker // If this structure changes, bump the version number for kTypeIdHistogram
27*635a8641SAndroid Build Coastguard Worker // in persistent_histogram_allocator.cc.
28*635a8641SAndroid Build Coastguard Worker //
29*635a8641SAndroid Build Coastguard Worker // Note that though these samples are individually consistent (through the use
30*635a8641SAndroid Build Coastguard Worker // of atomic operations on the counts), there is only "eventual consistency"
31*635a8641SAndroid Build Coastguard Worker // overall when multiple threads are accessing this data. That means that the
32*635a8641SAndroid Build Coastguard Worker // sum, redundant-count, etc. could be momentarily out-of-sync with the stored
33*635a8641SAndroid Build Coastguard Worker // counts but will settle to a consistent "steady state" once all threads have
34*635a8641SAndroid Build Coastguard Worker // exited this code.
35*635a8641SAndroid Build Coastguard Worker class BASE_EXPORT HistogramSamples {
36*635a8641SAndroid Build Coastguard Worker  public:
37*635a8641SAndroid Build Coastguard Worker   // A single bucket and count. To fit within a single atomic on 32-bit build
38*635a8641SAndroid Build Coastguard Worker   // architectures, both |bucket| and |count| are limited in size to 16 bits.
39*635a8641SAndroid Build Coastguard Worker   // This limits the functionality somewhat but if an entry can't fit then
40*635a8641SAndroid Build Coastguard Worker   // the full array of samples can be allocated and used.
41*635a8641SAndroid Build Coastguard Worker   struct SingleSample {
42*635a8641SAndroid Build Coastguard Worker     uint16_t bucket;
43*635a8641SAndroid Build Coastguard Worker     uint16_t count;
44*635a8641SAndroid Build Coastguard Worker   };
45*635a8641SAndroid Build Coastguard Worker 
46*635a8641SAndroid Build Coastguard Worker   // A structure for managing an atomic single sample. Because this is generally
47*635a8641SAndroid Build Coastguard Worker   // used in association with other atomic values, the defined methods use
48*635a8641SAndroid Build Coastguard Worker   // acquire/release operations to guarantee ordering with outside values.
49*635a8641SAndroid Build Coastguard Worker   union BASE_EXPORT AtomicSingleSample {
AtomicSingleSample()50*635a8641SAndroid Build Coastguard Worker     AtomicSingleSample() : as_atomic(0) {}
AtomicSingleSample(subtle::Atomic32 rhs)51*635a8641SAndroid Build Coastguard Worker     AtomicSingleSample(subtle::Atomic32 rhs) : as_atomic(rhs) {}
52*635a8641SAndroid Build Coastguard Worker 
53*635a8641SAndroid Build Coastguard Worker     // Returns the single sample in an atomic manner. This in an "acquire"
54*635a8641SAndroid Build Coastguard Worker     // load. The returned sample isn't shared and thus its fields can be safely
55*635a8641SAndroid Build Coastguard Worker     // accessed.
56*635a8641SAndroid Build Coastguard Worker     SingleSample Load() const;
57*635a8641SAndroid Build Coastguard Worker 
58*635a8641SAndroid Build Coastguard Worker     // Extracts the single sample in an atomic manner. If |disable| is true
59*635a8641SAndroid Build Coastguard Worker     // then this object will be set so it will never accumulate another value.
60*635a8641SAndroid Build Coastguard Worker     // This is "no barrier" so doesn't enforce ordering with other atomic ops.
61*635a8641SAndroid Build Coastguard Worker     SingleSample Extract(bool disable);
62*635a8641SAndroid Build Coastguard Worker 
63*635a8641SAndroid Build Coastguard Worker     // Adds a given count to the held bucket. If not possible, it returns false
64*635a8641SAndroid Build Coastguard Worker     // and leaves the parts unchanged. Once extracted/disabled, this always
65*635a8641SAndroid Build Coastguard Worker     // returns false. This in an "acquire/release" operation.
66*635a8641SAndroid Build Coastguard Worker     bool Accumulate(size_t bucket, HistogramBase::Count count);
67*635a8641SAndroid Build Coastguard Worker 
68*635a8641SAndroid Build Coastguard Worker     // Returns if the sample has been "disabled" (via Extract) and thus not
69*635a8641SAndroid Build Coastguard Worker     // allowed to accept further accumulation.
70*635a8641SAndroid Build Coastguard Worker     bool IsDisabled() const;
71*635a8641SAndroid Build Coastguard Worker 
72*635a8641SAndroid Build Coastguard Worker    private:
73*635a8641SAndroid Build Coastguard Worker     // union field: The actual sample bucket and count.
74*635a8641SAndroid Build Coastguard Worker     SingleSample as_parts;
75*635a8641SAndroid Build Coastguard Worker 
76*635a8641SAndroid Build Coastguard Worker     // union field: The sample as an atomic value. Atomic64 would provide
77*635a8641SAndroid Build Coastguard Worker     // more flexibility but isn't available on all builds. This can hold a
78*635a8641SAndroid Build Coastguard Worker     // special, internal "disabled" value indicating that it must not accept
79*635a8641SAndroid Build Coastguard Worker     // further accumulation.
80*635a8641SAndroid Build Coastguard Worker     subtle::Atomic32 as_atomic;
81*635a8641SAndroid Build Coastguard Worker   };
82*635a8641SAndroid Build Coastguard Worker 
83*635a8641SAndroid Build Coastguard Worker   // A structure of information about the data, common to all sample containers.
84*635a8641SAndroid Build Coastguard Worker   // Because of how this is used in persistent memory, it must be a POD object
85*635a8641SAndroid Build Coastguard Worker   // that makes sense when initialized to all zeros.
86*635a8641SAndroid Build Coastguard Worker   struct Metadata {
87*635a8641SAndroid Build Coastguard Worker     // Expected size for 32/64-bit check.
88*635a8641SAndroid Build Coastguard Worker     static constexpr size_t kExpectedInstanceSize = 24;
89*635a8641SAndroid Build Coastguard Worker 
90*635a8641SAndroid Build Coastguard Worker     // Initialized when the sample-set is first created with a value provided
91*635a8641SAndroid Build Coastguard Worker     // by the caller. It is generally used to identify the sample-set across
92*635a8641SAndroid Build Coastguard Worker     // threads and processes, though not necessarily uniquely as it is possible
93*635a8641SAndroid Build Coastguard Worker     // to have multiple sample-sets representing subsets of the data.
94*635a8641SAndroid Build Coastguard Worker     uint64_t id;
95*635a8641SAndroid Build Coastguard Worker 
96*635a8641SAndroid Build Coastguard Worker     // The sum of all the entries, effectivly the sum(sample * count) for
97*635a8641SAndroid Build Coastguard Worker     // all samples. Despite being atomic, no guarantees are made on the
98*635a8641SAndroid Build Coastguard Worker     // accuracy of this value; there may be races during histogram
99*635a8641SAndroid Build Coastguard Worker     // accumulation and snapshotting that we choose to accept. It should
100*635a8641SAndroid Build Coastguard Worker     // be treated as approximate.
101*635a8641SAndroid Build Coastguard Worker #ifdef ARCH_CPU_64_BITS
102*635a8641SAndroid Build Coastguard Worker     subtle::Atomic64 sum;
103*635a8641SAndroid Build Coastguard Worker #else
104*635a8641SAndroid Build Coastguard Worker     // 32-bit systems don't have atomic 64-bit operations. Use a basic type
105*635a8641SAndroid Build Coastguard Worker     // and don't worry about "shearing".
106*635a8641SAndroid Build Coastguard Worker     int64_t sum;
107*635a8641SAndroid Build Coastguard Worker #endif
108*635a8641SAndroid Build Coastguard Worker 
109*635a8641SAndroid Build Coastguard Worker     // A "redundant" count helps identify memory corruption. It redundantly
110*635a8641SAndroid Build Coastguard Worker     // stores the total number of samples accumulated in the histogram. We
111*635a8641SAndroid Build Coastguard Worker     // can compare this count to the sum of the counts (TotalCount() function),
112*635a8641SAndroid Build Coastguard Worker     // and detect problems. Note, depending on the implementation of different
113*635a8641SAndroid Build Coastguard Worker     // histogram types, there might be races during histogram accumulation
114*635a8641SAndroid Build Coastguard Worker     // and snapshotting that we choose to accept. In this case, the tallies
115*635a8641SAndroid Build Coastguard Worker     // might mismatch even when no memory corruption has happened.
116*635a8641SAndroid Build Coastguard Worker     HistogramBase::AtomicCount redundant_count;
117*635a8641SAndroid Build Coastguard Worker 
118*635a8641SAndroid Build Coastguard Worker     // A single histogram value and associated count. This allows histograms
119*635a8641SAndroid Build Coastguard Worker     // that typically report only a single value to not require full storage
120*635a8641SAndroid Build Coastguard Worker     // to be allocated.
121*635a8641SAndroid Build Coastguard Worker     AtomicSingleSample single_sample;  // 32 bits
122*635a8641SAndroid Build Coastguard Worker   };
123*635a8641SAndroid Build Coastguard Worker 
124*635a8641SAndroid Build Coastguard Worker   // Because structures held in persistent memory must be POD, there can be no
125*635a8641SAndroid Build Coastguard Worker   // default constructor to clear the fields. This derived class exists just
126*635a8641SAndroid Build Coastguard Worker   // to clear them when being allocated on the heap.
127*635a8641SAndroid Build Coastguard Worker   struct BASE_EXPORT LocalMetadata : Metadata {
128*635a8641SAndroid Build Coastguard Worker     LocalMetadata();
129*635a8641SAndroid Build Coastguard Worker   };
130*635a8641SAndroid Build Coastguard Worker 
131*635a8641SAndroid Build Coastguard Worker   HistogramSamples(uint64_t id, Metadata* meta);
132*635a8641SAndroid Build Coastguard Worker   virtual ~HistogramSamples();
133*635a8641SAndroid Build Coastguard Worker 
134*635a8641SAndroid Build Coastguard Worker   virtual void Accumulate(HistogramBase::Sample value,
135*635a8641SAndroid Build Coastguard Worker                           HistogramBase::Count count) = 0;
136*635a8641SAndroid Build Coastguard Worker   virtual HistogramBase::Count GetCount(HistogramBase::Sample value) const = 0;
137*635a8641SAndroid Build Coastguard Worker   virtual HistogramBase::Count TotalCount() const = 0;
138*635a8641SAndroid Build Coastguard Worker 
139*635a8641SAndroid Build Coastguard Worker   virtual void Add(const HistogramSamples& other);
140*635a8641SAndroid Build Coastguard Worker 
141*635a8641SAndroid Build Coastguard Worker   // Add from serialized samples.
142*635a8641SAndroid Build Coastguard Worker   virtual bool AddFromPickle(PickleIterator* iter);
143*635a8641SAndroid Build Coastguard Worker 
144*635a8641SAndroid Build Coastguard Worker   virtual void Subtract(const HistogramSamples& other);
145*635a8641SAndroid Build Coastguard Worker 
146*635a8641SAndroid Build Coastguard Worker   virtual std::unique_ptr<SampleCountIterator> Iterator() const = 0;
147*635a8641SAndroid Build Coastguard Worker   virtual void Serialize(Pickle* pickle) const;
148*635a8641SAndroid Build Coastguard Worker 
149*635a8641SAndroid Build Coastguard Worker   // Accessor fuctions.
id()150*635a8641SAndroid Build Coastguard Worker   uint64_t id() const { return meta_->id; }
sum()151*635a8641SAndroid Build Coastguard Worker   int64_t sum() const {
152*635a8641SAndroid Build Coastguard Worker #ifdef ARCH_CPU_64_BITS
153*635a8641SAndroid Build Coastguard Worker     return subtle::NoBarrier_Load(&meta_->sum);
154*635a8641SAndroid Build Coastguard Worker #else
155*635a8641SAndroid Build Coastguard Worker     return meta_->sum;
156*635a8641SAndroid Build Coastguard Worker #endif
157*635a8641SAndroid Build Coastguard Worker   }
redundant_count()158*635a8641SAndroid Build Coastguard Worker   HistogramBase::Count redundant_count() const {
159*635a8641SAndroid Build Coastguard Worker     return subtle::NoBarrier_Load(&meta_->redundant_count);
160*635a8641SAndroid Build Coastguard Worker   }
161*635a8641SAndroid Build Coastguard Worker 
162*635a8641SAndroid Build Coastguard Worker  protected:
163*635a8641SAndroid Build Coastguard Worker   enum NegativeSampleReason {
164*635a8641SAndroid Build Coastguard Worker     SAMPLES_HAVE_LOGGED_BUT_NOT_SAMPLE,
165*635a8641SAndroid Build Coastguard Worker     SAMPLES_SAMPLE_LESS_THAN_LOGGED,
166*635a8641SAndroid Build Coastguard Worker     SAMPLES_ADDED_NEGATIVE_COUNT,
167*635a8641SAndroid Build Coastguard Worker     SAMPLES_ADD_WENT_NEGATIVE,
168*635a8641SAndroid Build Coastguard Worker     SAMPLES_ADD_OVERFLOW,
169*635a8641SAndroid Build Coastguard Worker     SAMPLES_ACCUMULATE_NEGATIVE_COUNT,
170*635a8641SAndroid Build Coastguard Worker     SAMPLES_ACCUMULATE_WENT_NEGATIVE,
171*635a8641SAndroid Build Coastguard Worker     DEPRECATED_SAMPLES_ACCUMULATE_OVERFLOW,
172*635a8641SAndroid Build Coastguard Worker     SAMPLES_ACCUMULATE_OVERFLOW,
173*635a8641SAndroid Build Coastguard Worker     MAX_NEGATIVE_SAMPLE_REASONS
174*635a8641SAndroid Build Coastguard Worker   };
175*635a8641SAndroid Build Coastguard Worker 
176*635a8641SAndroid Build Coastguard Worker   // Based on |op| type, add or subtract sample counts data from the iterator.
177*635a8641SAndroid Build Coastguard Worker   enum Operator { ADD, SUBTRACT };
178*635a8641SAndroid Build Coastguard Worker   virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0;
179*635a8641SAndroid Build Coastguard Worker 
180*635a8641SAndroid Build Coastguard Worker   // Accumulates to the embedded single-sample field if possible. Returns true
181*635a8641SAndroid Build Coastguard Worker   // on success, false otherwise. Sum and redundant-count are also updated in
182*635a8641SAndroid Build Coastguard Worker   // the success case.
183*635a8641SAndroid Build Coastguard Worker   bool AccumulateSingleSample(HistogramBase::Sample value,
184*635a8641SAndroid Build Coastguard Worker                               HistogramBase::Count count,
185*635a8641SAndroid Build Coastguard Worker                               size_t bucket);
186*635a8641SAndroid Build Coastguard Worker 
187*635a8641SAndroid Build Coastguard Worker   // Atomically adjust the sum and redundant-count.
188*635a8641SAndroid Build Coastguard Worker   void IncreaseSumAndCount(int64_t sum, HistogramBase::Count count);
189*635a8641SAndroid Build Coastguard Worker 
190*635a8641SAndroid Build Coastguard Worker   // Record a negative-sample observation and the reason why.
191*635a8641SAndroid Build Coastguard Worker   void RecordNegativeSample(NegativeSampleReason reason,
192*635a8641SAndroid Build Coastguard Worker                             HistogramBase::Count increment);
193*635a8641SAndroid Build Coastguard Worker 
single_sample()194*635a8641SAndroid Build Coastguard Worker   AtomicSingleSample& single_sample() { return meta_->single_sample; }
single_sample()195*635a8641SAndroid Build Coastguard Worker   const AtomicSingleSample& single_sample() const {
196*635a8641SAndroid Build Coastguard Worker     return meta_->single_sample;
197*635a8641SAndroid Build Coastguard Worker   }
198*635a8641SAndroid Build Coastguard Worker 
meta()199*635a8641SAndroid Build Coastguard Worker   Metadata* meta() { return meta_; }
200*635a8641SAndroid Build Coastguard Worker 
201*635a8641SAndroid Build Coastguard Worker  private:
202*635a8641SAndroid Build Coastguard Worker   // Depending on derived class meta values can come from local stoarge or
203*635a8641SAndroid Build Coastguard Worker   // external storage in which case HistogramSamples class cannot take ownership
204*635a8641SAndroid Build Coastguard Worker   // of Metadata*.
205*635a8641SAndroid Build Coastguard Worker   Metadata* meta_;
206*635a8641SAndroid Build Coastguard Worker 
207*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(HistogramSamples);
208*635a8641SAndroid Build Coastguard Worker };
209*635a8641SAndroid Build Coastguard Worker 
210*635a8641SAndroid Build Coastguard Worker class BASE_EXPORT SampleCountIterator {
211*635a8641SAndroid Build Coastguard Worker  public:
212*635a8641SAndroid Build Coastguard Worker   virtual ~SampleCountIterator();
213*635a8641SAndroid Build Coastguard Worker 
214*635a8641SAndroid Build Coastguard Worker   virtual bool Done() const = 0;
215*635a8641SAndroid Build Coastguard Worker   virtual void Next() = 0;
216*635a8641SAndroid Build Coastguard Worker 
217*635a8641SAndroid Build Coastguard Worker   // Get the sample and count at current position.
218*635a8641SAndroid Build Coastguard Worker   // |min| |max| and |count| can be NULL if the value is not of interest.
219*635a8641SAndroid Build Coastguard Worker   // Note: |max| is int64_t because histograms support logged values in the
220*635a8641SAndroid Build Coastguard Worker   // full int32_t range and bucket max is exclusive, so it needs to support
221*635a8641SAndroid Build Coastguard Worker   // values up to MAXINT32+1.
222*635a8641SAndroid Build Coastguard Worker   // Requires: !Done();
223*635a8641SAndroid Build Coastguard Worker   virtual void Get(HistogramBase::Sample* min,
224*635a8641SAndroid Build Coastguard Worker                    int64_t* max,
225*635a8641SAndroid Build Coastguard Worker                    HistogramBase::Count* count) const = 0;
226*635a8641SAndroid Build Coastguard Worker   static_assert(std::numeric_limits<HistogramBase::Sample>::max() <
227*635a8641SAndroid Build Coastguard Worker                     std::numeric_limits<int64_t>::max(),
228*635a8641SAndroid Build Coastguard Worker                 "Get() |max| must be able to hold Histogram::Sample max + 1");
229*635a8641SAndroid Build Coastguard Worker 
230*635a8641SAndroid Build Coastguard Worker   // Get the index of current histogram bucket.
231*635a8641SAndroid Build Coastguard Worker   // For histograms that don't use predefined buckets, it returns false.
232*635a8641SAndroid Build Coastguard Worker   // Requires: !Done();
233*635a8641SAndroid Build Coastguard Worker   virtual bool GetBucketIndex(size_t* index) const;
234*635a8641SAndroid Build Coastguard Worker };
235*635a8641SAndroid Build Coastguard Worker 
236*635a8641SAndroid Build Coastguard Worker class BASE_EXPORT SingleSampleIterator : public SampleCountIterator {
237*635a8641SAndroid Build Coastguard Worker  public:
238*635a8641SAndroid Build Coastguard Worker   SingleSampleIterator(HistogramBase::Sample min,
239*635a8641SAndroid Build Coastguard Worker                        int64_t max,
240*635a8641SAndroid Build Coastguard Worker                        HistogramBase::Count count);
241*635a8641SAndroid Build Coastguard Worker   SingleSampleIterator(HistogramBase::Sample min,
242*635a8641SAndroid Build Coastguard Worker                        int64_t max,
243*635a8641SAndroid Build Coastguard Worker                        HistogramBase::Count count,
244*635a8641SAndroid Build Coastguard Worker                        size_t bucket_index);
245*635a8641SAndroid Build Coastguard Worker   ~SingleSampleIterator() override;
246*635a8641SAndroid Build Coastguard Worker 
247*635a8641SAndroid Build Coastguard Worker   // SampleCountIterator:
248*635a8641SAndroid Build Coastguard Worker   bool Done() const override;
249*635a8641SAndroid Build Coastguard Worker   void Next() override;
250*635a8641SAndroid Build Coastguard Worker   void Get(HistogramBase::Sample* min,
251*635a8641SAndroid Build Coastguard Worker            int64_t* max,
252*635a8641SAndroid Build Coastguard Worker            HistogramBase::Count* count) const override;
253*635a8641SAndroid Build Coastguard Worker 
254*635a8641SAndroid Build Coastguard Worker   // SampleVector uses predefined buckets so iterator can return bucket index.
255*635a8641SAndroid Build Coastguard Worker   bool GetBucketIndex(size_t* index) const override;
256*635a8641SAndroid Build Coastguard Worker 
257*635a8641SAndroid Build Coastguard Worker  private:
258*635a8641SAndroid Build Coastguard Worker   // Information about the single value to return.
259*635a8641SAndroid Build Coastguard Worker   const HistogramBase::Sample min_;
260*635a8641SAndroid Build Coastguard Worker   const int64_t max_;
261*635a8641SAndroid Build Coastguard Worker   const size_t bucket_index_;
262*635a8641SAndroid Build Coastguard Worker   HistogramBase::Count count_;
263*635a8641SAndroid Build Coastguard Worker };
264*635a8641SAndroid Build Coastguard Worker 
265*635a8641SAndroid Build Coastguard Worker }  // namespace base
266*635a8641SAndroid Build Coastguard Worker 
267*635a8641SAndroid Build Coastguard Worker #endif  // BASE_METRICS_HISTOGRAM_SAMPLES_H_
268