• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // SampleVector implements HistogramSamples interface. It is used by all
6 // Histogram based classes to store samples.
7 
8 #ifndef BASE_METRICS_SAMPLE_VECTOR_H_
9 #define BASE_METRICS_SAMPLE_VECTOR_H_
10 
11 #include <stddef.h>
12 #include <stdint.h>
13 
14 #include <atomic>
15 #include <memory>
16 #include <string>
17 #include <vector>
18 
19 #include "base/base_export.h"
20 #include "base/compiler_specific.h"
21 #include "base/gtest_prod_util.h"
22 #include "base/memory/raw_ptr.h"
23 #include "base/metrics/bucket_ranges.h"
24 #include "base/metrics/histogram_base.h"
25 #include "base/metrics/histogram_samples.h"
26 #include "base/metrics/persistent_memory_allocator.h"
27 
28 namespace base {
29 
30 class BucketRanges;
31 
32 class BASE_EXPORT SampleVectorBase : public HistogramSamples {
33  public:
34   SampleVectorBase(const SampleVectorBase&) = delete;
35   SampleVectorBase& operator=(const SampleVectorBase&) = delete;
36   ~SampleVectorBase() override;
37 
38   // HistogramSamples:
39   void Accumulate(HistogramBase::Sample value,
40                   HistogramBase::Count count) override;
41   HistogramBase::Count GetCount(HistogramBase::Sample value) const override;
42   HistogramBase::Count TotalCount() const override;
43   std::unique_ptr<SampleCountIterator> Iterator() const override;
44   std::unique_ptr<SampleCountIterator> ExtractingIterator() override;
45 
46   // Get count of a specific bucket.
47   HistogramBase::Count GetCountAtIndex(size_t bucket_index) const;
48 
49   // Access the bucket ranges held externally.
bucket_ranges()50   const BucketRanges* bucket_ranges() const { return bucket_ranges_; }
51 
52  protected:
53   SampleVectorBase(uint64_t id,
54                    Metadata* meta,
55                    const BucketRanges* bucket_ranges);
56   SampleVectorBase(uint64_t id,
57                    std::unique_ptr<Metadata> meta,
58                    const BucketRanges* bucket_ranges);
59 
60   bool AddSubtractImpl(
61       SampleCountIterator* iter,
62       HistogramSamples::Operator op) override;  // |op| is ADD or SUBTRACT.
63 
64   virtual size_t GetBucketIndex(HistogramBase::Sample value) const;
65 
66   // Moves the single-sample value to a mounted "counts" array.
67   void MoveSingleSampleToCounts();
68 
69   // Mounts (creating if necessary) an array of "counts" for multi-value
70   // storage.
71   void MountCountsStorageAndMoveSingleSample();
72 
73   // Mounts "counts" storage that already exists. This does not attempt to move
74   // any single-sample information to that storage as that would violate the
75   // "const" restriction that is often used to indicate read-only memory.
76   virtual bool MountExistingCountsStorage() const = 0;
77 
78   // Creates "counts" storage and returns a pointer to it. Ownership of the
79   // array remains with the called method but will never change. This must be
80   // called while some sort of lock is held to prevent reentry.
81   virtual HistogramBase::Count* CreateCountsStorageWhileLocked() = 0;
82 
counts()83   HistogramBase::AtomicCount* counts() {
84     return counts_.load(std::memory_order_acquire);
85   }
86 
counts()87   const HistogramBase::AtomicCount* counts() const {
88     return counts_.load(std::memory_order_acquire);
89   }
90 
set_counts(HistogramBase::AtomicCount * counts)91   void set_counts(HistogramBase::AtomicCount* counts) const {
92     counts_.store(counts, std::memory_order_release);
93   }
94 
counts_size()95   size_t counts_size() const { return bucket_ranges_->bucket_count(); }
96 
97  private:
98   friend class SampleVectorTest;
99   FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
100   FRIEND_TEST_ALL_PREFIXES(SharedHistogramTest, CorruptSampleCounts);
101 
102   // |counts_| is actually a pointer to a HistogramBase::AtomicCount array but
103   // is held as an atomic pointer for concurrency reasons. When combined with
104   // the single_sample held in the metadata, there are four possible states:
105   //   1) single_sample == zero, counts_ == null
106   //   2) single_sample != zero, counts_ == null
107   //   3) single_sample != zero, counts_ != null BUT IS EMPTY
108   //   4) single_sample == zero, counts_ != null and may have data
109   // Once |counts_| is set, it can never revert and any existing single-sample
110   // must be moved to this storage. It is mutable because changing it doesn't
111   // change the (const) data but must adapt if a non-const object causes the
112   // storage to be allocated and updated.
113   mutable std::atomic<HistogramBase::AtomicCount*> counts_{nullptr};
114 
115   // Shares the same BucketRanges with Histogram object.
116   const raw_ptr<const BucketRanges> bucket_ranges_;
117 };
118 
119 // A sample vector that uses local memory for the counts array.
120 class BASE_EXPORT SampleVector : public SampleVectorBase {
121  public:
122   explicit SampleVector(const BucketRanges* bucket_ranges);
123   SampleVector(uint64_t id, const BucketRanges* bucket_ranges);
124   SampleVector(const SampleVector&) = delete;
125   SampleVector& operator=(const SampleVector&) = delete;
126   ~SampleVector() override;
127 
128   // HistogramSamples:
129   bool IsDefinitelyEmpty() const override;
130 
131  private:
132   FRIEND_TEST_ALL_PREFIXES(SampleVectorTest, GetPeakBucketSize);
133 
134   // HistogramSamples:
135   std::string GetAsciiBody() const override;
136   std::string GetAsciiHeader(StringPiece histogram_name,
137                              int32_t flags) const override;
138 
139   // SampleVectorBase:
140   bool MountExistingCountsStorage() const override;
141   HistogramBase::Count* CreateCountsStorageWhileLocked() override;
142 
143   // Writes cumulative percentage information based on the number
144   // of past, current, and remaining bucket samples.
145   void WriteAsciiBucketContext(int64_t past,
146                                HistogramBase::Count current,
147                                int64_t remaining,
148                                uint32_t current_bucket_index,
149                                std::string* output) const;
150 
151   // Finds out how large (graphically) the largest bucket will appear to be.
152   double GetPeakBucketSize() const;
153 
bucket_count()154   size_t bucket_count() const { return bucket_ranges()->bucket_count(); }
155 
156   // Simple local storage for counts.
157   mutable std::vector<HistogramBase::AtomicCount> local_counts_;
158 };
159 
160 // A sample vector that uses persistent memory for the counts array.
161 class BASE_EXPORT PersistentSampleVector : public SampleVectorBase {
162  public:
163   PersistentSampleVector(uint64_t id,
164                          const BucketRanges* bucket_ranges,
165                          Metadata* meta,
166                          const DelayedPersistentAllocation& counts);
167   PersistentSampleVector(const PersistentSampleVector&) = delete;
168   PersistentSampleVector& operator=(const PersistentSampleVector&) = delete;
169   ~PersistentSampleVector() override;
170 
171   // HistogramSamples:
172   bool IsDefinitelyEmpty() const override;
173 
174  private:
175   // SampleVectorBase:
176   bool MountExistingCountsStorage() const override;
177   HistogramBase::Count* CreateCountsStorageWhileLocked() override;
178 
179   // Persistent storage for counts.
180   DelayedPersistentAllocation persistent_counts_;
181 };
182 
183 }  // namespace base
184 
185 #endif  // BASE_METRICS_SAMPLE_VECTOR_H_
186