blob: 23237b0fe40c2e7756238296cc4b12ccd0dc9d25 [file] [log] [blame]
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +09001// 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
avia6a6a682015-12-27 07:15:14 +09008#include <stddef.h>
9#include <stdint.h>
10
asvitkineb111a212017-05-04 06:37:37 +090011#include <limits>
dchengcc8e4d82016-04-05 06:25:51 +090012#include <memory>
13
bcwhiteca01de92015-12-11 03:36:34 +090014#include "base/atomicops.h"
avia6a6a682015-12-27 07:15:14 +090015#include "base/macros.h"
avia6a6a682015-12-27 07:15:14 +090016#include "base/metrics/histogram_base.h"
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +090017
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +090018namespace base {
19
brettwa4879472015-06-02 16:02:47 +090020class Pickle;
21class PickleIterator;
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +090022class SampleCountIterator;
23
bcwhited745f2b2016-02-25 01:28:39 +090024// 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
bcwhite248583d2016-03-16 11:37:45 +090027// in persistent_histogram_allocator.cc.
bcwhite4e70cfa2017-05-02 01:43:25 +090028//
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.
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +090035class BASE_EXPORT HistogramSamples {
36 public:
bcwhite4e70cfa2017-05-02 01:43:25 +090037 // 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.
Brian Whitee0583802017-08-26 02:58:37 +090049 union BASE_EXPORT AtomicSingleSample {
bcwhite4e70cfa2017-05-02 01:43:25 +090050 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.
bcwhiteca01de92015-12-11 03:36:34 +090086 struct Metadata {
piman064b27d2016-11-23 06:03:29 +090087 // Expected size for 32/64-bit check.
88 static constexpr size_t kExpectedInstanceSize = 24;
89
bcwhiteca01de92015-12-11 03:36:34 +090090 // 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.
bcwhite966dad32016-04-16 02:20:17 +0900101#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".
bcwhiteca01de92015-12-11 03:36:34 +0900106 int64_t sum;
bcwhite966dad32016-04-16 02:20:17 +0900107#endif
bcwhiteca01de92015-12-11 03:36:34 +0900108
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
bcwhite4e70cfa2017-05-02 01:43:25 +0900118 // 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
piman064b27d2016-11-23 06:03:29 +0900122 };
123
bcwhite4e70cfa2017-05-02 01:43:25 +0900124 // Because structures held in persistent memory must be POD, there can be no
piman064b27d2016-11-23 06:03:29 +0900125 // default constructor to clear the fields. This derived class exists just
126 // to clear them when being allocated on the heap.
bcwhite4e70cfa2017-05-02 01:43:25 +0900127 struct BASE_EXPORT LocalMetadata : Metadata {
128 LocalMetadata();
bcwhiteca01de92015-12-11 03:36:34 +0900129 };
130
bcwhiteca01de92015-12-11 03:36:34 +0900131 HistogramSamples(uint64_t id, Metadata* meta);
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900132 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
dchengcc8e4d82016-04-05 06:25:51 +0900146 virtual std::unique_ptr<SampleCountIterator> Iterator() const = 0;
Daniel Cheng51215ca2017-09-22 14:05:07 +0900147 virtual void Serialize(Pickle* pickle) const;
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900148
149 // Accessor fuctions.
bcwhiteca01de92015-12-11 03:36:34 +0900150 uint64_t id() const { return meta_->id; }
bcwhite966dad32016-04-16 02:20:17 +0900151 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 }
glider@chromium.org6761bae2014-01-21 16:59:28 +0900158 HistogramBase::Count redundant_count() const {
bcwhiteca01de92015-12-11 03:36:34 +0900159 return subtle::NoBarrier_Load(&meta_->redundant_count);
glider@chromium.org6761bae2014-01-21 16:59:28 +0900160 }
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900161
162 protected:
Brian White009187f2017-11-01 12:02:13 +0900163 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
kaiwang@chromium.orgec0e7272012-10-06 06:29:44 +0900176 // 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;
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900179
bcwhite4e70cfa2017-05-02 01:43:25 +0900180 // 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
Brian White009187f2017-11-01 12:02:13 +0900190 // Record a negative-sample observation and the reason why.
191 void RecordNegativeSample(NegativeSampleReason reason,
192 HistogramBase::Count increment);
193
bcwhite4e70cfa2017-05-02 01:43:25 +0900194 AtomicSingleSample& single_sample() { return meta_->single_sample; }
195 const AtomicSingleSample& single_sample() const {
196 return meta_->single_sample;
197 }
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900198
bcwhite4b460a82017-07-06 00:28:57 +0900199 Metadata* meta() { return meta_; }
200
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900201 private:
bcwhiteca01de92015-12-11 03:36:34 +0900202 Metadata* meta_;
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900203
bcwhiteca01de92015-12-11 03:36:34 +0900204 DISALLOW_COPY_AND_ASSIGN(HistogramSamples);
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900205};
206
207class BASE_EXPORT SampleCountIterator {
208 public:
209 virtual ~SampleCountIterator();
210
211 virtual bool Done() const = 0;
212 virtual void Next() = 0;
213
214 // Get the sample and count at current position.
215 // |min| |max| and |count| can be NULL if the value is not of interest.
asvitkineb111a212017-05-04 06:37:37 +0900216 // Note: |max| is int64_t because histograms support logged values in the
217 // full int32_t range and bucket max is exclusive, so it needs to support
218 // values up to MAXINT32+1.
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900219 // Requires: !Done();
220 virtual void Get(HistogramBase::Sample* min,
asvitkineb111a212017-05-04 06:37:37 +0900221 int64_t* max,
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900222 HistogramBase::Count* count) const = 0;
asvitkineb111a212017-05-04 06:37:37 +0900223 static_assert(std::numeric_limits<HistogramBase::Sample>::max() <
224 std::numeric_limits<int64_t>::max(),
225 "Get() |max| must be able to hold Histogram::Sample max + 1");
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900226
227 // Get the index of current histogram bucket.
228 // For histograms that don't use predefined buckets, it returns false.
229 // Requires: !Done();
230 virtual bool GetBucketIndex(size_t* index) const;
231};
232
bcwhite4e70cfa2017-05-02 01:43:25 +0900233class BASE_EXPORT SingleSampleIterator : public SampleCountIterator {
234 public:
235 SingleSampleIterator(HistogramBase::Sample min,
asvitkineb111a212017-05-04 06:37:37 +0900236 int64_t max,
bcwhite4e70cfa2017-05-02 01:43:25 +0900237 HistogramBase::Count count);
238 SingleSampleIterator(HistogramBase::Sample min,
asvitkineb111a212017-05-04 06:37:37 +0900239 int64_t max,
bcwhite4e70cfa2017-05-02 01:43:25 +0900240 HistogramBase::Count count,
241 size_t bucket_index);
242 ~SingleSampleIterator() override;
243
244 // SampleCountIterator:
245 bool Done() const override;
246 void Next() override;
247 void Get(HistogramBase::Sample* min,
asvitkineb111a212017-05-04 06:37:37 +0900248 int64_t* max,
bcwhite4e70cfa2017-05-02 01:43:25 +0900249 HistogramBase::Count* count) const override;
250
251 // SampleVector uses predefined buckets so iterator can return bucket index.
252 bool GetBucketIndex(size_t* index) const override;
253
254 private:
255 // Information about the single value to return.
256 const HistogramBase::Sample min_;
asvitkineb111a212017-05-04 06:37:37 +0900257 const int64_t max_;
bcwhite4e70cfa2017-05-02 01:43:25 +0900258 const size_t bucket_index_;
259 HistogramBase::Count count_;
260};
261
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900262} // namespace base
263
264#endif // BASE_METRICS_HISTOGRAM_SAMPLES_H_