• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // 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 <memory>
15 #include <vector>
16 
17 #include "base/atomicops.h"
18 #include "base/compiler_specific.h"
19 #include "base/gtest_prod_util.h"
20 #include "base/macros.h"
21 #include "base/metrics/bucket_ranges.h"
22 #include "base/metrics/histogram_base.h"
23 #include "base/metrics/histogram_samples.h"
24 #include "base/metrics/persistent_memory_allocator.h"
25 
26 namespace base {
27 
28 class BucketRanges;
29 
30 class BASE_EXPORT SampleVectorBase : public HistogramSamples {
31  public:
32   SampleVectorBase(uint64_t id,
33                    Metadata* meta,
34                    const BucketRanges* bucket_ranges);
35   ~SampleVectorBase() override;
36 
37   // HistogramSamples:
38   void Accumulate(HistogramBase::Sample value,
39                   HistogramBase::Count count) override;
40   HistogramBase::Count GetCount(HistogramBase::Sample value) const override;
41   HistogramBase::Count TotalCount() const override;
42   std::unique_ptr<SampleCountIterator> Iterator() const override;
43 
44   // Get count of a specific bucket.
45   HistogramBase::Count GetCountAtIndex(size_t bucket_index) const;
46 
47   // Access the bucket ranges held externally.
bucket_ranges()48   const BucketRanges* bucket_ranges() const { return bucket_ranges_; }
49 
50  protected:
51   bool AddSubtractImpl(
52       SampleCountIterator* iter,
53       HistogramSamples::Operator op) override;  // |op| is ADD or SUBTRACT.
54 
55   virtual size_t GetBucketIndex(HistogramBase::Sample value) const;
56 
57   // Moves the single-sample value to a mounted "counts" array.
58   void MoveSingleSampleToCounts();
59 
60   // Mounts (creating if necessary) an array of "counts" for multi-value
61   // storage.
62   void MountCountsStorageAndMoveSingleSample();
63 
64   // Mounts "counts" storage that already exists. This does not attempt to move
65   // any single-sample information to that storage as that would violate the
66   // "const" restriction that is often used to indicate read-only memory.
67   virtual bool MountExistingCountsStorage() const = 0;
68 
69   // Creates "counts" storage and returns a pointer to it. Ownership of the
70   // array remains with the called method but will never change. This must be
71   // called while some sort of lock is held to prevent reentry.
72   virtual HistogramBase::Count* CreateCountsStorageWhileLocked() = 0;
73 
counts()74   HistogramBase::AtomicCount* counts() {
75     return reinterpret_cast<HistogramBase::AtomicCount*>(
76         subtle::Acquire_Load(&counts_));
77   }
78 
counts()79   const HistogramBase::AtomicCount* counts() const {
80     return reinterpret_cast<HistogramBase::AtomicCount*>(
81         subtle::Acquire_Load(&counts_));
82   }
83 
set_counts(const HistogramBase::AtomicCount * counts)84   void set_counts(const HistogramBase::AtomicCount* counts) const {
85     subtle::Release_Store(&counts_, reinterpret_cast<uintptr_t>(counts));
86   }
87 
counts_size()88   size_t counts_size() const { return bucket_ranges_->bucket_count(); }
89 
90  private:
91   friend class SampleVectorTest;
92   FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
93   FRIEND_TEST_ALL_PREFIXES(SharedHistogramTest, CorruptSampleCounts);
94 
95   // |counts_| is actually a pointer to a HistogramBase::AtomicCount array but
96   // is held as an AtomicWord for concurrency reasons. When combined with the
97   // single_sample held in the metadata, there are four possible states:
98   //   1) single_sample == zero, counts_ == null
99   //   2) single_sample != zero, counts_ == null
100   //   3) single_sample != zero, counts_ != null BUT IS EMPTY
101   //   4) single_sample == zero, counts_ != null and may have data
102   // Once |counts_| is set, it can never revert and any existing single-sample
103   // must be moved to this storage. It is mutable because changing it doesn't
104   // change the (const) data but must adapt if a non-const object causes the
105   // storage to be allocated and updated.
106   mutable subtle::AtomicWord counts_ = 0;
107 
108   // Shares the same BucketRanges with Histogram object.
109   const BucketRanges* const bucket_ranges_;
110 
111   DISALLOW_COPY_AND_ASSIGN(SampleVectorBase);
112 };
113 
114 // A sample vector that uses local memory for the counts array.
115 class BASE_EXPORT SampleVector : public SampleVectorBase {
116  public:
117   explicit SampleVector(const BucketRanges* bucket_ranges);
118   SampleVector(uint64_t id, const BucketRanges* bucket_ranges);
119   ~SampleVector() override;
120 
121  private:
122   // SampleVectorBase:
123   bool MountExistingCountsStorage() const override;
124   HistogramBase::Count* CreateCountsStorageWhileLocked() override;
125 
126   // Simple local storage for counts.
127   mutable std::vector<HistogramBase::AtomicCount> local_counts_;
128 
129   DISALLOW_COPY_AND_ASSIGN(SampleVector);
130 };
131 
132 // A sample vector that uses persistent memory for the counts array.
133 class BASE_EXPORT PersistentSampleVector : public SampleVectorBase {
134  public:
135   PersistentSampleVector(uint64_t id,
136                          const BucketRanges* bucket_ranges,
137                          Metadata* meta,
138                          const DelayedPersistentAllocation& counts);
139   ~PersistentSampleVector() override;
140 
141  private:
142   // SampleVectorBase:
143   bool MountExistingCountsStorage() const override;
144   HistogramBase::Count* CreateCountsStorageWhileLocked() override;
145 
146   // Persistent storage for counts.
147   DelayedPersistentAllocation persistent_counts_;
148 
149   DISALLOW_COPY_AND_ASSIGN(PersistentSampleVector);
150 };
151 
152 // An iterator for sample vectors. This could be defined privately in the .cc
153 // file but is here for easy testing.
154 class BASE_EXPORT SampleVectorIterator : public SampleCountIterator {
155  public:
156   SampleVectorIterator(const std::vector<HistogramBase::AtomicCount>* counts,
157                        const BucketRanges* bucket_ranges);
158   SampleVectorIterator(const HistogramBase::AtomicCount* counts,
159                        size_t counts_size,
160                        const BucketRanges* bucket_ranges);
161   ~SampleVectorIterator() override;
162 
163   // SampleCountIterator implementation:
164   bool Done() const override;
165   void Next() override;
166   void Get(HistogramBase::Sample* min,
167            int64_t* max,
168            HistogramBase::Count* count) const override;
169 
170   // SampleVector uses predefined buckets, so iterator can return bucket index.
171   bool GetBucketIndex(size_t* index) const override;
172 
173  private:
174   void SkipEmptyBuckets();
175 
176   const HistogramBase::AtomicCount* counts_;
177   size_t counts_size_;
178   const BucketRanges* bucket_ranges_;
179 
180   size_t index_;
181 };
182 
183 }  // namespace base
184 
185 #endif  // BASE_METRICS_SAMPLE_VECTOR_H_
186