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