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