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 // SampleVector implements HistogramSamples interface. It is used by all 6*6777b538SAndroid Build Coastguard Worker // Histogram based classes to store samples. 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #ifndef BASE_METRICS_SAMPLE_VECTOR_H_ 9*6777b538SAndroid Build Coastguard Worker #define BASE_METRICS_SAMPLE_VECTOR_H_ 10*6777b538SAndroid Build Coastguard Worker 11*6777b538SAndroid Build Coastguard Worker #include <stddef.h> 12*6777b538SAndroid Build Coastguard Worker #include <stdint.h> 13*6777b538SAndroid Build Coastguard Worker 14*6777b538SAndroid Build Coastguard Worker #include <atomic> 15*6777b538SAndroid Build Coastguard Worker #include <memory> 16*6777b538SAndroid Build Coastguard Worker #include <string> 17*6777b538SAndroid Build Coastguard Worker #include <string_view> 18*6777b538SAndroid Build Coastguard Worker #include <vector> 19*6777b538SAndroid Build Coastguard Worker 20*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h" 21*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h" 22*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h" 23*6777b538SAndroid Build Coastguard Worker #include "base/gtest_prod_util.h" 24*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h" 25*6777b538SAndroid Build Coastguard Worker #include "base/metrics/bucket_ranges.h" 26*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_base.h" 27*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_samples.h" 28*6777b538SAndroid Build Coastguard Worker #include "base/metrics/persistent_memory_allocator.h" 29*6777b538SAndroid Build Coastguard Worker 30*6777b538SAndroid Build Coastguard Worker namespace base { 31*6777b538SAndroid Build Coastguard Worker 32*6777b538SAndroid Build Coastguard Worker class BucketRanges; 33*6777b538SAndroid Build Coastguard Worker 34*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT SampleVectorBase : public HistogramSamples { 35*6777b538SAndroid Build Coastguard Worker public: 36*6777b538SAndroid Build Coastguard Worker SampleVectorBase(const SampleVectorBase&) = delete; 37*6777b538SAndroid Build Coastguard Worker SampleVectorBase& operator=(const SampleVectorBase&) = delete; 38*6777b538SAndroid Build Coastguard Worker ~SampleVectorBase() override; 39*6777b538SAndroid Build Coastguard Worker 40*6777b538SAndroid Build Coastguard Worker // HistogramSamples: 41*6777b538SAndroid Build Coastguard Worker void Accumulate(HistogramBase::Sample value, 42*6777b538SAndroid Build Coastguard Worker HistogramBase::Count count) override; 43*6777b538SAndroid Build Coastguard Worker HistogramBase::Count GetCount(HistogramBase::Sample value) const override; 44*6777b538SAndroid Build Coastguard Worker HistogramBase::Count TotalCount() const override; 45*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SampleCountIterator> Iterator() const override; 46*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SampleCountIterator> ExtractingIterator() override; 47*6777b538SAndroid Build Coastguard Worker 48*6777b538SAndroid Build Coastguard Worker // Get count of a specific bucket. 49*6777b538SAndroid Build Coastguard Worker HistogramBase::Count GetCountAtIndex(size_t bucket_index) const; 50*6777b538SAndroid Build Coastguard Worker 51*6777b538SAndroid Build Coastguard Worker // Access the bucket ranges held externally. bucket_ranges()52*6777b538SAndroid Build Coastguard Worker const BucketRanges* bucket_ranges() const { return bucket_ranges_; } 53*6777b538SAndroid Build Coastguard Worker SingleSampleForTesting()54*6777b538SAndroid Build Coastguard Worker AtomicSingleSample* SingleSampleForTesting() { return &single_sample(); } 55*6777b538SAndroid Build Coastguard Worker 56*6777b538SAndroid Build Coastguard Worker protected: 57*6777b538SAndroid Build Coastguard Worker SampleVectorBase(uint64_t id, 58*6777b538SAndroid Build Coastguard Worker Metadata* meta, 59*6777b538SAndroid Build Coastguard Worker const BucketRanges* bucket_ranges); 60*6777b538SAndroid Build Coastguard Worker SampleVectorBase(uint64_t id, 61*6777b538SAndroid Build Coastguard Worker std::unique_ptr<Metadata> meta, 62*6777b538SAndroid Build Coastguard Worker const BucketRanges* bucket_ranges); 63*6777b538SAndroid Build Coastguard Worker 64*6777b538SAndroid Build Coastguard Worker bool AddSubtractImpl( 65*6777b538SAndroid Build Coastguard Worker SampleCountIterator* iter, 66*6777b538SAndroid Build Coastguard Worker HistogramSamples::Operator op) override; // |op| is ADD or SUBTRACT. 67*6777b538SAndroid Build Coastguard Worker 68*6777b538SAndroid Build Coastguard Worker virtual size_t GetBucketIndex(HistogramBase::Sample value) const; 69*6777b538SAndroid Build Coastguard Worker 70*6777b538SAndroid Build Coastguard Worker // Moves the single-sample value to a mounted "counts" array. 71*6777b538SAndroid Build Coastguard Worker void MoveSingleSampleToCounts(); 72*6777b538SAndroid Build Coastguard Worker 73*6777b538SAndroid Build Coastguard Worker // Mounts (creating if necessary) an array of "counts" for multi-value 74*6777b538SAndroid Build Coastguard Worker // storage. 75*6777b538SAndroid Build Coastguard Worker void MountCountsStorageAndMoveSingleSample(); 76*6777b538SAndroid Build Coastguard Worker 77*6777b538SAndroid Build Coastguard Worker // Mounts "counts" storage that already exists. This does not attempt to move 78*6777b538SAndroid Build Coastguard Worker // any single-sample information to that storage as that would violate the 79*6777b538SAndroid Build Coastguard Worker // "const" restriction that is often used to indicate read-only memory. 80*6777b538SAndroid Build Coastguard Worker virtual bool MountExistingCountsStorage() const = 0; 81*6777b538SAndroid Build Coastguard Worker 82*6777b538SAndroid Build Coastguard Worker // Creates "counts" storage and returns a span to it. The span's size must 83*6777b538SAndroid Build Coastguard Worker // be the number of counts required by the histogram. Ownership of the 84*6777b538SAndroid Build Coastguard Worker // array remains with the called method but will never change. This must be 85*6777b538SAndroid Build Coastguard Worker // called while some sort of lock is held to prevent reentry. 86*6777b538SAndroid Build Coastguard Worker virtual span<HistogramBase::Count> CreateCountsStorageWhileLocked() = 0; 87*6777b538SAndroid Build Coastguard Worker counts()88*6777b538SAndroid Build Coastguard Worker std::optional<span<HistogramBase::AtomicCount>> counts() { 89*6777b538SAndroid Build Coastguard Worker HistogramBase::AtomicCount* data = 90*6777b538SAndroid Build Coastguard Worker counts_data_.load(std::memory_order_acquire); 91*6777b538SAndroid Build Coastguard Worker if (data == nullptr) { 92*6777b538SAndroid Build Coastguard Worker return std::nullopt; 93*6777b538SAndroid Build Coastguard Worker } 94*6777b538SAndroid Build Coastguard Worker return std::make_optional(make_span(data, counts_size_)); 95*6777b538SAndroid Build Coastguard Worker } 96*6777b538SAndroid Build Coastguard Worker counts()97*6777b538SAndroid Build Coastguard Worker std::optional<span<const HistogramBase::AtomicCount>> counts() const { 98*6777b538SAndroid Build Coastguard Worker const HistogramBase::AtomicCount* data = 99*6777b538SAndroid Build Coastguard Worker counts_data_.load(std::memory_order_acquire); 100*6777b538SAndroid Build Coastguard Worker if (data == nullptr) { 101*6777b538SAndroid Build Coastguard Worker return std::nullopt; 102*6777b538SAndroid Build Coastguard Worker } 103*6777b538SAndroid Build Coastguard Worker return std::make_optional(make_span(data, counts_size_)); 104*6777b538SAndroid Build Coastguard Worker } 105*6777b538SAndroid Build Coastguard Worker set_counts(span<HistogramBase::AtomicCount> counts)106*6777b538SAndroid Build Coastguard Worker void set_counts(span<HistogramBase::AtomicCount> counts) const { 107*6777b538SAndroid Build Coastguard Worker CHECK_EQ(counts.size(), counts_size_); 108*6777b538SAndroid Build Coastguard Worker counts_data_.store(counts.data(), std::memory_order_release); 109*6777b538SAndroid Build Coastguard Worker } 110*6777b538SAndroid Build Coastguard Worker counts_size()111*6777b538SAndroid Build Coastguard Worker size_t counts_size() const { return counts_size_; } 112*6777b538SAndroid Build Coastguard Worker 113*6777b538SAndroid Build Coastguard Worker private: 114*6777b538SAndroid Build Coastguard Worker friend class SampleVectorTest; 115*6777b538SAndroid Build Coastguard Worker FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts); 116*6777b538SAndroid Build Coastguard Worker FRIEND_TEST_ALL_PREFIXES(SharedHistogramTest, CorruptSampleCounts); 117*6777b538SAndroid Build Coastguard Worker 118*6777b538SAndroid Build Coastguard Worker // Returns a reference into the `counts()` array. As `counts()` may be an 119*6777b538SAndroid Build Coastguard Worker // empty optional until the array is populated, `counts()` must be checked for 120*6777b538SAndroid Build Coastguard Worker // having a value before calling `counts_at()`, or this method may CHECK-fail. counts_at(size_t index)121*6777b538SAndroid Build Coastguard Worker const HistogramBase::AtomicCount& counts_at(size_t index) const { 122*6777b538SAndroid Build Coastguard Worker return (counts().value())[index]; 123*6777b538SAndroid Build Coastguard Worker } counts_at(size_t index)124*6777b538SAndroid Build Coastguard Worker HistogramBase::AtomicCount& counts_at(size_t index) { 125*6777b538SAndroid Build Coastguard Worker return (counts().value())[index]; 126*6777b538SAndroid Build Coastguard Worker } 127*6777b538SAndroid Build Coastguard Worker 128*6777b538SAndroid Build Coastguard Worker // Shares the same BucketRanges with Histogram object. 129*6777b538SAndroid Build Coastguard Worker const raw_ptr<const BucketRanges> bucket_ranges_; 130*6777b538SAndroid Build Coastguard Worker 131*6777b538SAndroid Build Coastguard Worker // The number of counts in the histogram. Once `counts_data_` becomes 132*6777b538SAndroid Build Coastguard Worker // non-null, this is the number of values in the `counts_data_` array that 133*6777b538SAndroid Build Coastguard Worker // are usable by the SampleVector. 134*6777b538SAndroid Build Coastguard Worker const size_t counts_size_; 135*6777b538SAndroid Build Coastguard Worker 136*6777b538SAndroid Build Coastguard Worker // `counts_data_` is a pointer to a `HistogramBase::AtomicCount` array that is 137*6777b538SAndroid Build Coastguard Worker // held as an atomic pointer for concurrency reasons. When combined with the 138*6777b538SAndroid Build Coastguard Worker // single_sample held in the metadata, there are four possible states: 139*6777b538SAndroid Build Coastguard Worker // 1) single_sample == zero, counts_ == null 140*6777b538SAndroid Build Coastguard Worker // 2) single_sample != zero, counts_ == null 141*6777b538SAndroid Build Coastguard Worker // 3) single_sample != zero, counts_ != null BUT IS EMPTY 142*6777b538SAndroid Build Coastguard Worker // 4) single_sample == zero, counts_ != null and may have data 143*6777b538SAndroid Build Coastguard Worker // Once `counts_data_` is set to a value, it can never be changed and any 144*6777b538SAndroid Build Coastguard Worker // existing single-sample must be moved to this storage. It is mutable because 145*6777b538SAndroid Build Coastguard Worker // changing it doesn't change the (const) data but must adapt if a non-const 146*6777b538SAndroid Build Coastguard Worker // object causes the storage to be allocated and updated. 147*6777b538SAndroid Build Coastguard Worker // 148*6777b538SAndroid Build Coastguard Worker // Held as raw pointer in atomic, instead of as a span, to avoid locks. The 149*6777b538SAndroid Build Coastguard Worker // `counts_size_` is the size of the would-be span, which is CHECKd when 150*6777b538SAndroid Build Coastguard Worker // setting the pointer, and used to recreate a span on the way out. 151*6777b538SAndroid Build Coastguard Worker mutable std::atomic<HistogramBase::AtomicCount*> counts_data_; 152*6777b538SAndroid Build Coastguard Worker }; 153*6777b538SAndroid Build Coastguard Worker 154*6777b538SAndroid Build Coastguard Worker // A sample vector that uses local memory for the counts array. 155*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT SampleVector : public SampleVectorBase { 156*6777b538SAndroid Build Coastguard Worker public: 157*6777b538SAndroid Build Coastguard Worker explicit SampleVector(const BucketRanges* bucket_ranges); 158*6777b538SAndroid Build Coastguard Worker SampleVector(uint64_t id, const BucketRanges* bucket_ranges); 159*6777b538SAndroid Build Coastguard Worker SampleVector(const SampleVector&) = delete; 160*6777b538SAndroid Build Coastguard Worker SampleVector& operator=(const SampleVector&) = delete; 161*6777b538SAndroid Build Coastguard Worker ~SampleVector() override; 162*6777b538SAndroid Build Coastguard Worker 163*6777b538SAndroid Build Coastguard Worker // HistogramSamples: 164*6777b538SAndroid Build Coastguard Worker bool IsDefinitelyEmpty() const override; 165*6777b538SAndroid Build Coastguard Worker 166*6777b538SAndroid Build Coastguard Worker private: 167*6777b538SAndroid Build Coastguard Worker FRIEND_TEST_ALL_PREFIXES(SampleVectorTest, GetPeakBucketSize); 168*6777b538SAndroid Build Coastguard Worker 169*6777b538SAndroid Build Coastguard Worker // HistogramSamples: 170*6777b538SAndroid Build Coastguard Worker std::string GetAsciiBody() const override; 171*6777b538SAndroid Build Coastguard Worker std::string GetAsciiHeader(std::string_view histogram_name, 172*6777b538SAndroid Build Coastguard Worker int32_t flags) const override; 173*6777b538SAndroid Build Coastguard Worker 174*6777b538SAndroid Build Coastguard Worker // SampleVectorBase: 175*6777b538SAndroid Build Coastguard Worker bool MountExistingCountsStorage() const override; 176*6777b538SAndroid Build Coastguard Worker span<HistogramBase::Count> CreateCountsStorageWhileLocked() override; 177*6777b538SAndroid Build Coastguard Worker 178*6777b538SAndroid Build Coastguard Worker // Writes cumulative percentage information based on the number 179*6777b538SAndroid Build Coastguard Worker // of past, current, and remaining bucket samples. 180*6777b538SAndroid Build Coastguard Worker void WriteAsciiBucketContext(int64_t past, 181*6777b538SAndroid Build Coastguard Worker HistogramBase::Count current, 182*6777b538SAndroid Build Coastguard Worker int64_t remaining, 183*6777b538SAndroid Build Coastguard Worker uint32_t current_bucket_index, 184*6777b538SAndroid Build Coastguard Worker std::string* output) const; 185*6777b538SAndroid Build Coastguard Worker 186*6777b538SAndroid Build Coastguard Worker // Finds out how large (graphically) the largest bucket will appear to be. 187*6777b538SAndroid Build Coastguard Worker double GetPeakBucketSize() const; 188*6777b538SAndroid Build Coastguard Worker bucket_count()189*6777b538SAndroid Build Coastguard Worker size_t bucket_count() const { return bucket_ranges()->bucket_count(); } 190*6777b538SAndroid Build Coastguard Worker 191*6777b538SAndroid Build Coastguard Worker // Simple local storage for counts. 192*6777b538SAndroid Build Coastguard Worker mutable std::vector<HistogramBase::AtomicCount> local_counts_; 193*6777b538SAndroid Build Coastguard Worker }; 194*6777b538SAndroid Build Coastguard Worker 195*6777b538SAndroid Build Coastguard Worker // A sample vector that uses persistent memory for the counts array. 196*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT PersistentSampleVector : public SampleVectorBase { 197*6777b538SAndroid Build Coastguard Worker public: 198*6777b538SAndroid Build Coastguard Worker PersistentSampleVector(uint64_t id, 199*6777b538SAndroid Build Coastguard Worker const BucketRanges* bucket_ranges, 200*6777b538SAndroid Build Coastguard Worker Metadata* meta, 201*6777b538SAndroid Build Coastguard Worker const DelayedPersistentAllocation& counts); 202*6777b538SAndroid Build Coastguard Worker PersistentSampleVector(const PersistentSampleVector&) = delete; 203*6777b538SAndroid Build Coastguard Worker PersistentSampleVector& operator=(const PersistentSampleVector&) = delete; 204*6777b538SAndroid Build Coastguard Worker ~PersistentSampleVector() override; 205*6777b538SAndroid Build Coastguard Worker 206*6777b538SAndroid Build Coastguard Worker // HistogramSamples: 207*6777b538SAndroid Build Coastguard Worker bool IsDefinitelyEmpty() const override; 208*6777b538SAndroid Build Coastguard Worker 209*6777b538SAndroid Build Coastguard Worker private: 210*6777b538SAndroid Build Coastguard Worker // SampleVectorBase: 211*6777b538SAndroid Build Coastguard Worker bool MountExistingCountsStorage() const override; 212*6777b538SAndroid Build Coastguard Worker span<HistogramBase::Count> CreateCountsStorageWhileLocked() override; 213*6777b538SAndroid Build Coastguard Worker 214*6777b538SAndroid Build Coastguard Worker // Persistent storage for counts. 215*6777b538SAndroid Build Coastguard Worker DelayedPersistentAllocation persistent_counts_; 216*6777b538SAndroid Build Coastguard Worker }; 217*6777b538SAndroid Build Coastguard Worker 218*6777b538SAndroid Build Coastguard Worker } // namespace base 219*6777b538SAndroid Build Coastguard Worker 220*6777b538SAndroid Build Coastguard Worker #endif // BASE_METRICS_SAMPLE_VECTOR_H_ 221