Home | History | Annotate | Download | only in metrics
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_METRICS_HISTOGRAM_SAMPLES_H_
      6 #define BASE_METRICS_HISTOGRAM_SAMPLES_H_
      7 
      8 #include <stddef.h>
      9 #include <stdint.h>
     10 
     11 #include <limits>
     12 #include <memory>
     13 
     14 #include "base/atomicops.h"
     15 #include "base/macros.h"
     16 #include "base/metrics/histogram_base.h"
     17 
     18 namespace base {
     19 
     20 class Pickle;
     21 class PickleIterator;
     22 class SampleCountIterator;
     23 
     24 // HistogramSamples is a container storing all samples of a histogram. All
     25 // elements must be of a fixed width to ensure 32/64-bit interoperability.
     26 // If this structure changes, bump the version number for kTypeIdHistogram
     27 // in persistent_histogram_allocator.cc.
     28 //
     29 // Note that though these samples are individually consistent (through the use
     30 // of atomic operations on the counts), there is only "eventual consistency"
     31 // overall when multiple threads are accessing this data. That means that the
     32 // sum, redundant-count, etc. could be momentarily out-of-sync with the stored
     33 // counts but will settle to a consistent "steady state" once all threads have
     34 // exited this code.
     35 class BASE_EXPORT HistogramSamples {
     36  public:
     37   // A single bucket and count. To fit within a single atomic on 32-bit build
     38   // architectures, both |bucket| and |count| are limited in size to 16 bits.
     39   // This limits the functionality somewhat but if an entry can't fit then
     40   // the full array of samples can be allocated and used.
     41   struct SingleSample {
     42     uint16_t bucket;
     43     uint16_t count;
     44   };
     45 
     46   // A structure for managing an atomic single sample. Because this is generally
     47   // used in association with other atomic values, the defined methods use
     48   // acquire/release operations to guarantee ordering with outside values.
     49   union BASE_EXPORT AtomicSingleSample {
     50     AtomicSingleSample() : as_atomic(0) {}
     51     AtomicSingleSample(subtle::Atomic32 rhs) : as_atomic(rhs) {}
     52 
     53     // Returns the single sample in an atomic manner. This in an "acquire"
     54     // load. The returned sample isn't shared and thus its fields can be safely
     55     // accessed.
     56     SingleSample Load() const;
     57 
     58     // Extracts the single sample in an atomic manner. If |disable| is true
     59     // then this object will be set so it will never accumulate another value.
     60     // This is "no barrier" so doesn't enforce ordering with other atomic ops.
     61     SingleSample Extract(bool disable);
     62 
     63     // Adds a given count to the held bucket. If not possible, it returns false
     64     // and leaves the parts unchanged. Once extracted/disabled, this always
     65     // returns false. This in an "acquire/release" operation.
     66     bool Accumulate(size_t bucket, HistogramBase::Count count);
     67 
     68     // Returns if the sample has been "disabled" (via Extract) and thus not
     69     // allowed to accept further accumulation.
     70     bool IsDisabled() const;
     71 
     72    private:
     73     // union field: The actual sample bucket and count.
     74     SingleSample as_parts;
     75 
     76     // union field: The sample as an atomic value. Atomic64 would provide
     77     // more flexibility but isn't available on all builds. This can hold a
     78     // special, internal "disabled" value indicating that it must not accept
     79     // further accumulation.
     80     subtle::Atomic32 as_atomic;
     81   };
     82 
     83   // A structure of information about the data, common to all sample containers.
     84   // Because of how this is used in persistent memory, it must be a POD object
     85   // that makes sense when initialized to all zeros.
     86   struct Metadata {
     87     // Expected size for 32/64-bit check.
     88     static constexpr size_t kExpectedInstanceSize = 24;
     89 
     90     // Initialized when the sample-set is first created with a value provided
     91     // by the caller. It is generally used to identify the sample-set across
     92     // threads and processes, though not necessarily uniquely as it is possible
     93     // to have multiple sample-sets representing subsets of the data.
     94     uint64_t id;
     95 
     96     // The sum of all the entries, effectivly the sum(sample * count) for
     97     // all samples. Despite being atomic, no guarantees are made on the
     98     // accuracy of this value; there may be races during histogram
     99     // accumulation and snapshotting that we choose to accept. It should
    100     // be treated as approximate.
    101 #ifdef ARCH_CPU_64_BITS
    102     subtle::Atomic64 sum;
    103 #else
    104     // 32-bit systems don't have atomic 64-bit operations. Use a basic type
    105     // and don't worry about "shearing".
    106     int64_t sum;
    107 #endif
    108 
    109     // A "redundant" count helps identify memory corruption. It redundantly
    110     // stores the total number of samples accumulated in the histogram. We
    111     // can compare this count to the sum of the counts (TotalCount() function),
    112     // and detect problems. Note, depending on the implementation of different
    113     // histogram types, there might be races during histogram accumulation
    114     // and snapshotting that we choose to accept. In this case, the tallies
    115     // might mismatch even when no memory corruption has happened.
    116     HistogramBase::AtomicCount redundant_count;
    117 
    118     // A single histogram value and associated count. This allows histograms
    119     // that typically report only a single value to not require full storage
    120     // to be allocated.
    121     AtomicSingleSample single_sample;  // 32 bits
    122   };
    123 
    124   // Because structures held in persistent memory must be POD, there can be no
    125   // default constructor to clear the fields. This derived class exists just
    126   // to clear them when being allocated on the heap.
    127   struct BASE_EXPORT LocalMetadata : Metadata {
    128     LocalMetadata();
    129   };
    130 
    131   HistogramSamples(uint64_t id, Metadata* meta);
    132   virtual ~HistogramSamples();
    133 
    134   virtual void Accumulate(HistogramBase::Sample value,
    135                           HistogramBase::Count count) = 0;
    136   virtual HistogramBase::Count GetCount(HistogramBase::Sample value) const = 0;
    137   virtual HistogramBase::Count TotalCount() const = 0;
    138 
    139   virtual void Add(const HistogramSamples& other);
    140 
    141   // Add from serialized samples.
    142   virtual bool AddFromPickle(PickleIterator* iter);
    143 
    144   virtual void Subtract(const HistogramSamples& other);
    145 
    146   virtual std::unique_ptr<SampleCountIterator> Iterator() const = 0;
    147   virtual void Serialize(Pickle* pickle) const;
    148 
    149   // Accessor fuctions.
    150   uint64_t id() const { return meta_->id; }
    151   int64_t sum() const {
    152 #ifdef ARCH_CPU_64_BITS
    153     return subtle::NoBarrier_Load(&meta_->sum);
    154 #else
    155     return meta_->sum;
    156 #endif
    157   }
    158   HistogramBase::Count redundant_count() const {
    159     return subtle::NoBarrier_Load(&meta_->redundant_count);
    160   }
    161 
    162  protected:
    163   enum NegativeSampleReason {
    164     SAMPLES_HAVE_LOGGED_BUT_NOT_SAMPLE,
    165     SAMPLES_SAMPLE_LESS_THAN_LOGGED,
    166     SAMPLES_ADDED_NEGATIVE_COUNT,
    167     SAMPLES_ADD_WENT_NEGATIVE,
    168     SAMPLES_ADD_OVERFLOW,
    169     SAMPLES_ACCUMULATE_NEGATIVE_COUNT,
    170     SAMPLES_ACCUMULATE_WENT_NEGATIVE,
    171     DEPRECATED_SAMPLES_ACCUMULATE_OVERFLOW,
    172     SAMPLES_ACCUMULATE_OVERFLOW,
    173     MAX_NEGATIVE_SAMPLE_REASONS
    174   };
    175 
    176   // Based on |op| type, add or subtract sample counts data from the iterator.
    177   enum Operator { ADD, SUBTRACT };
    178   virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0;
    179 
    180   // Accumulates to the embedded single-sample field if possible. Returns true
    181   // on success, false otherwise. Sum and redundant-count are also updated in
    182   // the success case.
    183   bool AccumulateSingleSample(HistogramBase::Sample value,
    184                               HistogramBase::Count count,
    185                               size_t bucket);
    186 
    187   // Atomically adjust the sum and redundant-count.
    188   void IncreaseSumAndCount(int64_t sum, HistogramBase::Count count);
    189 
    190   // Record a negative-sample observation and the reason why.
    191   void RecordNegativeSample(NegativeSampleReason reason,
    192                             HistogramBase::Count increment);
    193 
    194   AtomicSingleSample& single_sample() { return meta_->single_sample; }
    195   const AtomicSingleSample& single_sample() const {
    196     return meta_->single_sample;
    197   }
    198 
    199   Metadata* meta() { return meta_; }
    200 
    201  private:
    202   // Depending on derived class meta values can come from local stoarge or
    203   // external storage in which case HistogramSamples class cannot take ownership
    204   // of Metadata*.
    205   Metadata* meta_;
    206 
    207   DISALLOW_COPY_AND_ASSIGN(HistogramSamples);
    208 };
    209 
    210 class BASE_EXPORT SampleCountIterator {
    211  public:
    212   virtual ~SampleCountIterator();
    213 
    214   virtual bool Done() const = 0;
    215   virtual void Next() = 0;
    216 
    217   // Get the sample and count at current position.
    218   // |min| |max| and |count| can be NULL if the value is not of interest.
    219   // Note: |max| is int64_t because histograms support logged values in the
    220   // full int32_t range and bucket max is exclusive, so it needs to support
    221   // values up to MAXINT32+1.
    222   // Requires: !Done();
    223   virtual void Get(HistogramBase::Sample* min,
    224                    int64_t* max,
    225                    HistogramBase::Count* count) const = 0;
    226   static_assert(std::numeric_limits<HistogramBase::Sample>::max() <
    227                     std::numeric_limits<int64_t>::max(),
    228                 "Get() |max| must be able to hold Histogram::Sample max + 1");
    229 
    230   // Get the index of current histogram bucket.
    231   // For histograms that don't use predefined buckets, it returns false.
    232   // Requires: !Done();
    233   virtual bool GetBucketIndex(size_t* index) const;
    234 };
    235 
    236 class BASE_EXPORT SingleSampleIterator : public SampleCountIterator {
    237  public:
    238   SingleSampleIterator(HistogramBase::Sample min,
    239                        int64_t max,
    240                        HistogramBase::Count count);
    241   SingleSampleIterator(HistogramBase::Sample min,
    242                        int64_t max,
    243                        HistogramBase::Count count,
    244                        size_t bucket_index);
    245   ~SingleSampleIterator() override;
    246 
    247   // SampleCountIterator:
    248   bool Done() const override;
    249   void Next() override;
    250   void Get(HistogramBase::Sample* min,
    251            int64_t* max,
    252            HistogramBase::Count* count) const override;
    253 
    254   // SampleVector uses predefined buckets so iterator can return bucket index.
    255   bool GetBucketIndex(size_t* index) const override;
    256 
    257  private:
    258   // Information about the single value to return.
    259   const HistogramBase::Sample min_;
    260   const int64_t max_;
    261   const size_t bucket_index_;
    262   HistogramBase::Count count_;
    263 };
    264 
    265 }  // namespace base
    266 
    267 #endif  // BASE_METRICS_HISTOGRAM_SAMPLES_H_
    268