xref: /aosp_15_r20/external/libchrome/base/metrics/sample_vector.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 // SampleVector implements HistogramSamples interface. It is used by all
6*635a8641SAndroid Build Coastguard Worker // Histogram based classes to store samples.
7*635a8641SAndroid Build Coastguard Worker 
8*635a8641SAndroid Build Coastguard Worker #ifndef BASE_METRICS_SAMPLE_VECTOR_H_
9*635a8641SAndroid Build Coastguard Worker #define BASE_METRICS_SAMPLE_VECTOR_H_
10*635a8641SAndroid Build Coastguard Worker 
11*635a8641SAndroid Build Coastguard Worker #include <stddef.h>
12*635a8641SAndroid Build Coastguard Worker #include <stdint.h>
13*635a8641SAndroid Build Coastguard Worker 
14*635a8641SAndroid Build Coastguard Worker #include <memory>
15*635a8641SAndroid Build Coastguard Worker #include <vector>
16*635a8641SAndroid Build Coastguard Worker 
17*635a8641SAndroid Build Coastguard Worker #include "base/atomicops.h"
18*635a8641SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
19*635a8641SAndroid Build Coastguard Worker #include "base/gtest_prod_util.h"
20*635a8641SAndroid Build Coastguard Worker #include "base/macros.h"
21*635a8641SAndroid Build Coastguard Worker #include "base/metrics/bucket_ranges.h"
22*635a8641SAndroid Build Coastguard Worker #include "base/metrics/histogram_base.h"
23*635a8641SAndroid Build Coastguard Worker #include "base/metrics/histogram_samples.h"
24*635a8641SAndroid Build Coastguard Worker #include "base/metrics/persistent_memory_allocator.h"
25*635a8641SAndroid Build Coastguard Worker 
26*635a8641SAndroid Build Coastguard Worker namespace base {
27*635a8641SAndroid Build Coastguard Worker 
28*635a8641SAndroid Build Coastguard Worker class BucketRanges;
29*635a8641SAndroid Build Coastguard Worker 
30*635a8641SAndroid Build Coastguard Worker class BASE_EXPORT SampleVectorBase : public HistogramSamples {
31*635a8641SAndroid Build Coastguard Worker  public:
32*635a8641SAndroid Build Coastguard Worker   SampleVectorBase(uint64_t id,
33*635a8641SAndroid Build Coastguard Worker                    Metadata* meta,
34*635a8641SAndroid Build Coastguard Worker                    const BucketRanges* bucket_ranges);
35*635a8641SAndroid Build Coastguard Worker   ~SampleVectorBase() override;
36*635a8641SAndroid Build Coastguard Worker 
37*635a8641SAndroid Build Coastguard Worker   // HistogramSamples:
38*635a8641SAndroid Build Coastguard Worker   void Accumulate(HistogramBase::Sample value,
39*635a8641SAndroid Build Coastguard Worker                   HistogramBase::Count count) override;
40*635a8641SAndroid Build Coastguard Worker   HistogramBase::Count GetCount(HistogramBase::Sample value) const override;
41*635a8641SAndroid Build Coastguard Worker   HistogramBase::Count TotalCount() const override;
42*635a8641SAndroid Build Coastguard Worker   std::unique_ptr<SampleCountIterator> Iterator() const override;
43*635a8641SAndroid Build Coastguard Worker 
44*635a8641SAndroid Build Coastguard Worker   // Get count of a specific bucket.
45*635a8641SAndroid Build Coastguard Worker   HistogramBase::Count GetCountAtIndex(size_t bucket_index) const;
46*635a8641SAndroid Build Coastguard Worker 
47*635a8641SAndroid Build Coastguard Worker   // Access the bucket ranges held externally.
bucket_ranges()48*635a8641SAndroid Build Coastguard Worker   const BucketRanges* bucket_ranges() const { return bucket_ranges_; }
49*635a8641SAndroid Build Coastguard Worker 
50*635a8641SAndroid Build Coastguard Worker  protected:
51*635a8641SAndroid Build Coastguard Worker   bool AddSubtractImpl(
52*635a8641SAndroid Build Coastguard Worker       SampleCountIterator* iter,
53*635a8641SAndroid Build Coastguard Worker       HistogramSamples::Operator op) override;  // |op| is ADD or SUBTRACT.
54*635a8641SAndroid Build Coastguard Worker 
55*635a8641SAndroid Build Coastguard Worker   virtual size_t GetBucketIndex(HistogramBase::Sample value) const;
56*635a8641SAndroid Build Coastguard Worker 
57*635a8641SAndroid Build Coastguard Worker   // Moves the single-sample value to a mounted "counts" array.
58*635a8641SAndroid Build Coastguard Worker   void MoveSingleSampleToCounts();
59*635a8641SAndroid Build Coastguard Worker 
60*635a8641SAndroid Build Coastguard Worker   // Mounts (creating if necessary) an array of "counts" for multi-value
61*635a8641SAndroid Build Coastguard Worker   // storage.
62*635a8641SAndroid Build Coastguard Worker   void MountCountsStorageAndMoveSingleSample();
63*635a8641SAndroid Build Coastguard Worker 
64*635a8641SAndroid Build Coastguard Worker   // Mounts "counts" storage that already exists. This does not attempt to move
65*635a8641SAndroid Build Coastguard Worker   // any single-sample information to that storage as that would violate the
66*635a8641SAndroid Build Coastguard Worker   // "const" restriction that is often used to indicate read-only memory.
67*635a8641SAndroid Build Coastguard Worker   virtual bool MountExistingCountsStorage() const = 0;
68*635a8641SAndroid Build Coastguard Worker 
69*635a8641SAndroid Build Coastguard Worker   // Creates "counts" storage and returns a pointer to it. Ownership of the
70*635a8641SAndroid Build Coastguard Worker   // array remains with the called method but will never change. This must be
71*635a8641SAndroid Build Coastguard Worker   // called while some sort of lock is held to prevent reentry.
72*635a8641SAndroid Build Coastguard Worker   virtual HistogramBase::Count* CreateCountsStorageWhileLocked() = 0;
73*635a8641SAndroid Build Coastguard Worker 
counts()74*635a8641SAndroid Build Coastguard Worker   HistogramBase::AtomicCount* counts() {
75*635a8641SAndroid Build Coastguard Worker     return reinterpret_cast<HistogramBase::AtomicCount*>(
76*635a8641SAndroid Build Coastguard Worker         subtle::Acquire_Load(&counts_));
77*635a8641SAndroid Build Coastguard Worker   }
78*635a8641SAndroid Build Coastguard Worker 
counts()79*635a8641SAndroid Build Coastguard Worker   const HistogramBase::AtomicCount* counts() const {
80*635a8641SAndroid Build Coastguard Worker     return reinterpret_cast<HistogramBase::AtomicCount*>(
81*635a8641SAndroid Build Coastguard Worker         subtle::Acquire_Load(&counts_));
82*635a8641SAndroid Build Coastguard Worker   }
83*635a8641SAndroid Build Coastguard Worker 
set_counts(const HistogramBase::AtomicCount * counts)84*635a8641SAndroid Build Coastguard Worker   void set_counts(const HistogramBase::AtomicCount* counts) const {
85*635a8641SAndroid Build Coastguard Worker     subtle::Release_Store(&counts_, reinterpret_cast<uintptr_t>(counts));
86*635a8641SAndroid Build Coastguard Worker   }
87*635a8641SAndroid Build Coastguard Worker 
counts_size()88*635a8641SAndroid Build Coastguard Worker   size_t counts_size() const { return bucket_ranges_->bucket_count(); }
89*635a8641SAndroid Build Coastguard Worker 
90*635a8641SAndroid Build Coastguard Worker  private:
91*635a8641SAndroid Build Coastguard Worker   friend class SampleVectorTest;
92*635a8641SAndroid Build Coastguard Worker   FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
93*635a8641SAndroid Build Coastguard Worker   FRIEND_TEST_ALL_PREFIXES(SharedHistogramTest, CorruptSampleCounts);
94*635a8641SAndroid Build Coastguard Worker 
95*635a8641SAndroid Build Coastguard Worker   // |counts_| is actually a pointer to a HistogramBase::AtomicCount array but
96*635a8641SAndroid Build Coastguard Worker   // is held as an AtomicWord for concurrency reasons. When combined with the
97*635a8641SAndroid Build Coastguard Worker   // single_sample held in the metadata, there are four possible states:
98*635a8641SAndroid Build Coastguard Worker   //   1) single_sample == zero, counts_ == null
99*635a8641SAndroid Build Coastguard Worker   //   2) single_sample != zero, counts_ == null
100*635a8641SAndroid Build Coastguard Worker   //   3) single_sample != zero, counts_ != null BUT IS EMPTY
101*635a8641SAndroid Build Coastguard Worker   //   4) single_sample == zero, counts_ != null and may have data
102*635a8641SAndroid Build Coastguard Worker   // Once |counts_| is set, it can never revert and any existing single-sample
103*635a8641SAndroid Build Coastguard Worker   // must be moved to this storage. It is mutable because changing it doesn't
104*635a8641SAndroid Build Coastguard Worker   // change the (const) data but must adapt if a non-const object causes the
105*635a8641SAndroid Build Coastguard Worker   // storage to be allocated and updated.
106*635a8641SAndroid Build Coastguard Worker   mutable subtle::AtomicWord counts_ = 0;
107*635a8641SAndroid Build Coastguard Worker 
108*635a8641SAndroid Build Coastguard Worker   // Shares the same BucketRanges with Histogram object.
109*635a8641SAndroid Build Coastguard Worker   const BucketRanges* const bucket_ranges_;
110*635a8641SAndroid Build Coastguard Worker 
111*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(SampleVectorBase);
112*635a8641SAndroid Build Coastguard Worker };
113*635a8641SAndroid Build Coastguard Worker 
114*635a8641SAndroid Build Coastguard Worker // A sample vector that uses local memory for the counts array.
115*635a8641SAndroid Build Coastguard Worker class BASE_EXPORT SampleVector : public SampleVectorBase {
116*635a8641SAndroid Build Coastguard Worker  public:
117*635a8641SAndroid Build Coastguard Worker   explicit SampleVector(const BucketRanges* bucket_ranges);
118*635a8641SAndroid Build Coastguard Worker   SampleVector(uint64_t id, const BucketRanges* bucket_ranges);
119*635a8641SAndroid Build Coastguard Worker   ~SampleVector() override;
120*635a8641SAndroid Build Coastguard Worker 
121*635a8641SAndroid Build Coastguard Worker  private:
122*635a8641SAndroid Build Coastguard Worker   // SampleVectorBase:
123*635a8641SAndroid Build Coastguard Worker   bool MountExistingCountsStorage() const override;
124*635a8641SAndroid Build Coastguard Worker   HistogramBase::Count* CreateCountsStorageWhileLocked() override;
125*635a8641SAndroid Build Coastguard Worker 
126*635a8641SAndroid Build Coastguard Worker   // Simple local storage for counts.
127*635a8641SAndroid Build Coastguard Worker   mutable std::vector<HistogramBase::AtomicCount> local_counts_;
128*635a8641SAndroid Build Coastguard Worker 
129*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(SampleVector);
130*635a8641SAndroid Build Coastguard Worker };
131*635a8641SAndroid Build Coastguard Worker 
132*635a8641SAndroid Build Coastguard Worker // A sample vector that uses persistent memory for the counts array.
133*635a8641SAndroid Build Coastguard Worker class BASE_EXPORT PersistentSampleVector : public SampleVectorBase {
134*635a8641SAndroid Build Coastguard Worker  public:
135*635a8641SAndroid Build Coastguard Worker   PersistentSampleVector(uint64_t id,
136*635a8641SAndroid Build Coastguard Worker                          const BucketRanges* bucket_ranges,
137*635a8641SAndroid Build Coastguard Worker                          Metadata* meta,
138*635a8641SAndroid Build Coastguard Worker                          const DelayedPersistentAllocation& counts);
139*635a8641SAndroid Build Coastguard Worker   ~PersistentSampleVector() override;
140*635a8641SAndroid Build Coastguard Worker 
141*635a8641SAndroid Build Coastguard Worker  private:
142*635a8641SAndroid Build Coastguard Worker   // SampleVectorBase:
143*635a8641SAndroid Build Coastguard Worker   bool MountExistingCountsStorage() const override;
144*635a8641SAndroid Build Coastguard Worker   HistogramBase::Count* CreateCountsStorageWhileLocked() override;
145*635a8641SAndroid Build Coastguard Worker 
146*635a8641SAndroid Build Coastguard Worker   // Persistent storage for counts.
147*635a8641SAndroid Build Coastguard Worker   DelayedPersistentAllocation persistent_counts_;
148*635a8641SAndroid Build Coastguard Worker 
149*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(PersistentSampleVector);
150*635a8641SAndroid Build Coastguard Worker };
151*635a8641SAndroid Build Coastguard Worker 
152*635a8641SAndroid Build Coastguard Worker // An iterator for sample vectors. This could be defined privately in the .cc
153*635a8641SAndroid Build Coastguard Worker // file but is here for easy testing.
154*635a8641SAndroid Build Coastguard Worker class BASE_EXPORT SampleVectorIterator : public SampleCountIterator {
155*635a8641SAndroid Build Coastguard Worker  public:
156*635a8641SAndroid Build Coastguard Worker   SampleVectorIterator(const std::vector<HistogramBase::AtomicCount>* counts,
157*635a8641SAndroid Build Coastguard Worker                        const BucketRanges* bucket_ranges);
158*635a8641SAndroid Build Coastguard Worker   SampleVectorIterator(const HistogramBase::AtomicCount* counts,
159*635a8641SAndroid Build Coastguard Worker                        size_t counts_size,
160*635a8641SAndroid Build Coastguard Worker                        const BucketRanges* bucket_ranges);
161*635a8641SAndroid Build Coastguard Worker   ~SampleVectorIterator() override;
162*635a8641SAndroid Build Coastguard Worker 
163*635a8641SAndroid Build Coastguard Worker   // SampleCountIterator implementation:
164*635a8641SAndroid Build Coastguard Worker   bool Done() const override;
165*635a8641SAndroid Build Coastguard Worker   void Next() override;
166*635a8641SAndroid Build Coastguard Worker   void Get(HistogramBase::Sample* min,
167*635a8641SAndroid Build Coastguard Worker            int64_t* max,
168*635a8641SAndroid Build Coastguard Worker            HistogramBase::Count* count) const override;
169*635a8641SAndroid Build Coastguard Worker 
170*635a8641SAndroid Build Coastguard Worker   // SampleVector uses predefined buckets, so iterator can return bucket index.
171*635a8641SAndroid Build Coastguard Worker   bool GetBucketIndex(size_t* index) const override;
172*635a8641SAndroid Build Coastguard Worker 
173*635a8641SAndroid Build Coastguard Worker  private:
174*635a8641SAndroid Build Coastguard Worker   void SkipEmptyBuckets();
175*635a8641SAndroid Build Coastguard Worker 
176*635a8641SAndroid Build Coastguard Worker   const HistogramBase::AtomicCount* counts_;
177*635a8641SAndroid Build Coastguard Worker   size_t counts_size_;
178*635a8641SAndroid Build Coastguard Worker   const BucketRanges* bucket_ranges_;
179*635a8641SAndroid Build Coastguard Worker 
180*635a8641SAndroid Build Coastguard Worker   size_t index_;
181*635a8641SAndroid Build Coastguard Worker };
182*635a8641SAndroid Build Coastguard Worker 
183*635a8641SAndroid Build Coastguard Worker }  // namespace base
184*635a8641SAndroid Build Coastguard Worker 
185*635a8641SAndroid Build Coastguard Worker #endif  // BASE_METRICS_SAMPLE_VECTOR_H_
186