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