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 <memory>
12 
13 #include "base/atomicops.h"
14 #include "base/macros.h"
15 #include "base/metrics/histogram_base.h"
16 
17 namespace base {
18 
19 class Pickle;
20 class PickleIterator;
21 class SampleCountIterator;
22 
23 // HistogramSamples is a container storing all samples of a histogram. All
24 // elements must be of a fixed width to ensure 32/64-bit interoperability.
25 // If this structure changes, bump the version number for kTypeIdHistogram
26 // in persistent_histogram_allocator.cc.
27 class BASE_EXPORT HistogramSamples {
28  public:
29   struct Metadata {
30     // Expected size for 32/64-bit check.
31     static constexpr size_t kExpectedInstanceSize = 24;
32 
33     // Initialized when the sample-set is first created with a value provided
34     // by the caller. It is generally used to identify the sample-set across
35     // threads and processes, though not necessarily uniquely as it is possible
36     // to have multiple sample-sets representing subsets of the data.
37     uint64_t id;
38 
39     // The sum of all the entries, effectivly the sum(sample * count) for
40     // all samples. Despite being atomic, no guarantees are made on the
41     // accuracy of this value; there may be races during histogram
42     // accumulation and snapshotting that we choose to accept. It should
43     // be treated as approximate.
44 #ifdef ARCH_CPU_64_BITS
45     subtle::Atomic64 sum;
46 #else
47     // 32-bit systems don't have atomic 64-bit operations. Use a basic type
48     // and don't worry about "shearing".
49     int64_t sum;
50 #endif
51 
52     // A "redundant" count helps identify memory corruption. It redundantly
53     // stores the total number of samples accumulated in the histogram. We
54     // can compare this count to the sum of the counts (TotalCount() function),
55     // and detect problems. Note, depending on the implementation of different
56     // histogram types, there might be races during histogram accumulation
57     // and snapshotting that we choose to accept. In this case, the tallies
58     // might mismatch even when no memory corruption has happened.
59     HistogramBase::AtomicCount redundant_count;
60 
61     // 4 bytes of padding to explicitly extend this structure to a multiple of
62     // 64-bits. This is required to ensure the structure is the same size on
63     // both 32-bit and 64-bit builds.
64     char padding[4];
65   };
66 
67   // Because sturctures held in persistent memory must be POD, there can be no
68   // default constructor to clear the fields. This derived class exists just
69   // to clear them when being allocated on the heap.
70   struct LocalMetadata : Metadata {
LocalMetadataLocalMetadata71     LocalMetadata() {
72       id = 0;
73       sum = 0;
74       redundant_count = 0;
75     }
76   };
77 
78   explicit HistogramSamples(uint64_t id);
79   HistogramSamples(uint64_t id, Metadata* meta);
80   virtual ~HistogramSamples();
81 
82   virtual void Accumulate(HistogramBase::Sample value,
83                           HistogramBase::Count count) = 0;
84   virtual HistogramBase::Count GetCount(HistogramBase::Sample value) const = 0;
85   virtual HistogramBase::Count TotalCount() const = 0;
86 
87   virtual void Add(const HistogramSamples& other);
88 
89   // Add from serialized samples.
90   virtual bool AddFromPickle(PickleIterator* iter);
91 
92   virtual void Subtract(const HistogramSamples& other);
93 
94   virtual std::unique_ptr<SampleCountIterator> Iterator() const = 0;
95   virtual bool Serialize(Pickle* pickle) const;
96 
97   // Accessor fuctions.
id()98   uint64_t id() const { return meta_->id; }
sum()99   int64_t sum() const {
100 #ifdef ARCH_CPU_64_BITS
101     return subtle::NoBarrier_Load(&meta_->sum);
102 #else
103     return meta_->sum;
104 #endif
105   }
redundant_count()106   HistogramBase::Count redundant_count() const {
107     return subtle::NoBarrier_Load(&meta_->redundant_count);
108   }
109 
110  protected:
111   // Based on |op| type, add or subtract sample counts data from the iterator.
112   enum Operator { ADD, SUBTRACT };
113   virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0;
114 
115   void IncreaseSum(int64_t diff);
116   void IncreaseRedundantCount(HistogramBase::Count diff);
117 
118  private:
119   // In order to support histograms shared through an external memory segment,
120   // meta values may be the local storage or external storage depending on the
121   // wishes of the derived class.
122   LocalMetadata local_meta_;
123   Metadata* meta_;
124 
125   DISALLOW_COPY_AND_ASSIGN(HistogramSamples);
126 };
127 
128 class BASE_EXPORT SampleCountIterator {
129  public:
130   virtual ~SampleCountIterator();
131 
132   virtual bool Done() const = 0;
133   virtual void Next() = 0;
134 
135   // Get the sample and count at current position.
136   // |min| |max| and |count| can be NULL if the value is not of interest.
137   // Requires: !Done();
138   virtual void Get(HistogramBase::Sample* min,
139                    HistogramBase::Sample* max,
140                    HistogramBase::Count* count) const = 0;
141 
142   // Get the index of current histogram bucket.
143   // For histograms that don't use predefined buckets, it returns false.
144   // Requires: !Done();
145   virtual bool GetBucketIndex(size_t* index) const;
146 };
147 
148 }  // namespace base
149 
150 #endif  // BASE_METRICS_HISTOGRAM_SAMPLES_H_
151