1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker #include "base/metrics/histogram_samples.h"
6*635a8641SAndroid Build Coastguard Worker
7*635a8641SAndroid Build Coastguard Worker #include <limits>
8*635a8641SAndroid Build Coastguard Worker
9*635a8641SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
10*635a8641SAndroid Build Coastguard Worker #include "base/metrics/histogram_functions.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/numerics/safe_math.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/pickle.h"
15*635a8641SAndroid Build Coastguard Worker
16*635a8641SAndroid Build Coastguard Worker namespace base {
17*635a8641SAndroid Build Coastguard Worker
18*635a8641SAndroid Build Coastguard Worker namespace {
19*635a8641SAndroid Build Coastguard Worker
20*635a8641SAndroid Build Coastguard Worker // A shorthand constant for the max value of size_t.
21*635a8641SAndroid Build Coastguard Worker constexpr size_t kSizeMax = std::numeric_limits<size_t>::max();
22*635a8641SAndroid Build Coastguard Worker
23*635a8641SAndroid Build Coastguard Worker // A constant stored in an AtomicSingleSample (as_atomic) to indicate that the
24*635a8641SAndroid Build Coastguard Worker // sample is "disabled" and no further accumulation should be done with it. The
25*635a8641SAndroid Build Coastguard Worker // value is chosen such that it will be MAX_UINT16 for both |bucket| & |count|,
26*635a8641SAndroid Build Coastguard Worker // and thus less likely to conflict with real use. Conflicts are explicitly
27*635a8641SAndroid Build Coastguard Worker // handled in the code but it's worth making them as unlikely as possible.
28*635a8641SAndroid Build Coastguard Worker constexpr int32_t kDisabledSingleSample = -1;
29*635a8641SAndroid Build Coastguard Worker
30*635a8641SAndroid Build Coastguard Worker class SampleCountPickleIterator : public SampleCountIterator {
31*635a8641SAndroid Build Coastguard Worker public:
32*635a8641SAndroid Build Coastguard Worker explicit SampleCountPickleIterator(PickleIterator* iter);
33*635a8641SAndroid Build Coastguard Worker
34*635a8641SAndroid Build Coastguard Worker bool Done() const override;
35*635a8641SAndroid Build Coastguard Worker void Next() override;
36*635a8641SAndroid Build Coastguard Worker void Get(HistogramBase::Sample* min,
37*635a8641SAndroid Build Coastguard Worker int64_t* max,
38*635a8641SAndroid Build Coastguard Worker HistogramBase::Count* count) const override;
39*635a8641SAndroid Build Coastguard Worker
40*635a8641SAndroid Build Coastguard Worker private:
41*635a8641SAndroid Build Coastguard Worker PickleIterator* const iter_;
42*635a8641SAndroid Build Coastguard Worker
43*635a8641SAndroid Build Coastguard Worker HistogramBase::Sample min_;
44*635a8641SAndroid Build Coastguard Worker int64_t max_;
45*635a8641SAndroid Build Coastguard Worker HistogramBase::Count count_;
46*635a8641SAndroid Build Coastguard Worker bool is_done_;
47*635a8641SAndroid Build Coastguard Worker };
48*635a8641SAndroid Build Coastguard Worker
SampleCountPickleIterator(PickleIterator * iter)49*635a8641SAndroid Build Coastguard Worker SampleCountPickleIterator::SampleCountPickleIterator(PickleIterator* iter)
50*635a8641SAndroid Build Coastguard Worker : iter_(iter),
51*635a8641SAndroid Build Coastguard Worker is_done_(false) {
52*635a8641SAndroid Build Coastguard Worker Next();
53*635a8641SAndroid Build Coastguard Worker }
54*635a8641SAndroid Build Coastguard Worker
Done() const55*635a8641SAndroid Build Coastguard Worker bool SampleCountPickleIterator::Done() const {
56*635a8641SAndroid Build Coastguard Worker return is_done_;
57*635a8641SAndroid Build Coastguard Worker }
58*635a8641SAndroid Build Coastguard Worker
Next()59*635a8641SAndroid Build Coastguard Worker void SampleCountPickleIterator::Next() {
60*635a8641SAndroid Build Coastguard Worker DCHECK(!Done());
61*635a8641SAndroid Build Coastguard Worker if (!iter_->ReadInt(&min_) || !iter_->ReadInt64(&max_) ||
62*635a8641SAndroid Build Coastguard Worker !iter_->ReadInt(&count_)) {
63*635a8641SAndroid Build Coastguard Worker is_done_ = true;
64*635a8641SAndroid Build Coastguard Worker }
65*635a8641SAndroid Build Coastguard Worker }
66*635a8641SAndroid Build Coastguard Worker
Get(HistogramBase::Sample * min,int64_t * max,HistogramBase::Count * count) const67*635a8641SAndroid Build Coastguard Worker void SampleCountPickleIterator::Get(HistogramBase::Sample* min,
68*635a8641SAndroid Build Coastguard Worker int64_t* max,
69*635a8641SAndroid Build Coastguard Worker HistogramBase::Count* count) const {
70*635a8641SAndroid Build Coastguard Worker DCHECK(!Done());
71*635a8641SAndroid Build Coastguard Worker *min = min_;
72*635a8641SAndroid Build Coastguard Worker *max = max_;
73*635a8641SAndroid Build Coastguard Worker *count = count_;
74*635a8641SAndroid Build Coastguard Worker }
75*635a8641SAndroid Build Coastguard Worker
76*635a8641SAndroid Build Coastguard Worker } // namespace
77*635a8641SAndroid Build Coastguard Worker
78*635a8641SAndroid Build Coastguard Worker static_assert(sizeof(HistogramSamples::AtomicSingleSample) ==
79*635a8641SAndroid Build Coastguard Worker sizeof(subtle::Atomic32),
80*635a8641SAndroid Build Coastguard Worker "AtomicSingleSample isn't 32 bits");
81*635a8641SAndroid Build Coastguard Worker
Load() const82*635a8641SAndroid Build Coastguard Worker HistogramSamples::SingleSample HistogramSamples::AtomicSingleSample::Load()
83*635a8641SAndroid Build Coastguard Worker const {
84*635a8641SAndroid Build Coastguard Worker AtomicSingleSample single_sample = subtle::Acquire_Load(&as_atomic);
85*635a8641SAndroid Build Coastguard Worker
86*635a8641SAndroid Build Coastguard Worker // If the sample was extracted/disabled, it's still zero to the outside.
87*635a8641SAndroid Build Coastguard Worker if (single_sample.as_atomic == kDisabledSingleSample)
88*635a8641SAndroid Build Coastguard Worker single_sample.as_atomic = 0;
89*635a8641SAndroid Build Coastguard Worker
90*635a8641SAndroid Build Coastguard Worker return single_sample.as_parts;
91*635a8641SAndroid Build Coastguard Worker }
92*635a8641SAndroid Build Coastguard Worker
Extract(bool disable)93*635a8641SAndroid Build Coastguard Worker HistogramSamples::SingleSample HistogramSamples::AtomicSingleSample::Extract(
94*635a8641SAndroid Build Coastguard Worker bool disable) {
95*635a8641SAndroid Build Coastguard Worker AtomicSingleSample single_sample = subtle::NoBarrier_AtomicExchange(
96*635a8641SAndroid Build Coastguard Worker &as_atomic, disable ? kDisabledSingleSample : 0);
97*635a8641SAndroid Build Coastguard Worker if (single_sample.as_atomic == kDisabledSingleSample)
98*635a8641SAndroid Build Coastguard Worker single_sample.as_atomic = 0;
99*635a8641SAndroid Build Coastguard Worker return single_sample.as_parts;
100*635a8641SAndroid Build Coastguard Worker }
101*635a8641SAndroid Build Coastguard Worker
Accumulate(size_t bucket,HistogramBase::Count count)102*635a8641SAndroid Build Coastguard Worker bool HistogramSamples::AtomicSingleSample::Accumulate(
103*635a8641SAndroid Build Coastguard Worker size_t bucket,
104*635a8641SAndroid Build Coastguard Worker HistogramBase::Count count) {
105*635a8641SAndroid Build Coastguard Worker if (count == 0)
106*635a8641SAndroid Build Coastguard Worker return true;
107*635a8641SAndroid Build Coastguard Worker
108*635a8641SAndroid Build Coastguard Worker // Convert the parameters to 16-bit variables because it's all 16-bit below.
109*635a8641SAndroid Build Coastguard Worker // To support decrements/subtractions, divide the |count| into sign/value and
110*635a8641SAndroid Build Coastguard Worker // do the proper operation below. The alternative is to change the single-
111*635a8641SAndroid Build Coastguard Worker // sample's count to be a signed integer (int16_t) and just add an int16_t
112*635a8641SAndroid Build Coastguard Worker // |count16| but that is somewhat wasteful given that the single-sample is
113*635a8641SAndroid Build Coastguard Worker // never expected to have a count less than zero.
114*635a8641SAndroid Build Coastguard Worker if (count < -std::numeric_limits<uint16_t>::max() ||
115*635a8641SAndroid Build Coastguard Worker count > std::numeric_limits<uint16_t>::max() ||
116*635a8641SAndroid Build Coastguard Worker bucket > std::numeric_limits<uint16_t>::max()) {
117*635a8641SAndroid Build Coastguard Worker return false;
118*635a8641SAndroid Build Coastguard Worker }
119*635a8641SAndroid Build Coastguard Worker bool count_is_negative = count < 0;
120*635a8641SAndroid Build Coastguard Worker uint16_t count16 = static_cast<uint16_t>(count_is_negative ? -count : count);
121*635a8641SAndroid Build Coastguard Worker uint16_t bucket16 = static_cast<uint16_t>(bucket);
122*635a8641SAndroid Build Coastguard Worker
123*635a8641SAndroid Build Coastguard Worker // A local, unshared copy of the single-sample is necessary so the parts
124*635a8641SAndroid Build Coastguard Worker // can be manipulated without worrying about atomicity.
125*635a8641SAndroid Build Coastguard Worker AtomicSingleSample single_sample;
126*635a8641SAndroid Build Coastguard Worker
127*635a8641SAndroid Build Coastguard Worker bool sample_updated;
128*635a8641SAndroid Build Coastguard Worker do {
129*635a8641SAndroid Build Coastguard Worker subtle::Atomic32 original = subtle::Acquire_Load(&as_atomic);
130*635a8641SAndroid Build Coastguard Worker if (original == kDisabledSingleSample)
131*635a8641SAndroid Build Coastguard Worker return false;
132*635a8641SAndroid Build Coastguard Worker single_sample.as_atomic = original;
133*635a8641SAndroid Build Coastguard Worker if (single_sample.as_atomic != 0) {
134*635a8641SAndroid Build Coastguard Worker // Only the same bucket (parameter and stored) can be counted multiple
135*635a8641SAndroid Build Coastguard Worker // times.
136*635a8641SAndroid Build Coastguard Worker if (single_sample.as_parts.bucket != bucket16)
137*635a8641SAndroid Build Coastguard Worker return false;
138*635a8641SAndroid Build Coastguard Worker } else {
139*635a8641SAndroid Build Coastguard Worker // The |single_ sample| was zero so becomes the |bucket| parameter, the
140*635a8641SAndroid Build Coastguard Worker // contents of which were checked above to fit in 16 bits.
141*635a8641SAndroid Build Coastguard Worker single_sample.as_parts.bucket = bucket16;
142*635a8641SAndroid Build Coastguard Worker }
143*635a8641SAndroid Build Coastguard Worker
144*635a8641SAndroid Build Coastguard Worker // Update count, making sure that it doesn't overflow.
145*635a8641SAndroid Build Coastguard Worker CheckedNumeric<uint16_t> new_count(single_sample.as_parts.count);
146*635a8641SAndroid Build Coastguard Worker if (count_is_negative)
147*635a8641SAndroid Build Coastguard Worker new_count -= count16;
148*635a8641SAndroid Build Coastguard Worker else
149*635a8641SAndroid Build Coastguard Worker new_count += count16;
150*635a8641SAndroid Build Coastguard Worker if (!new_count.AssignIfValid(&single_sample.as_parts.count))
151*635a8641SAndroid Build Coastguard Worker return false;
152*635a8641SAndroid Build Coastguard Worker
153*635a8641SAndroid Build Coastguard Worker // Don't let this become equivalent to the "disabled" value.
154*635a8641SAndroid Build Coastguard Worker if (single_sample.as_atomic == kDisabledSingleSample)
155*635a8641SAndroid Build Coastguard Worker return false;
156*635a8641SAndroid Build Coastguard Worker
157*635a8641SAndroid Build Coastguard Worker // Store the updated single-sample back into memory. |existing| is what
158*635a8641SAndroid Build Coastguard Worker // was in that memory location at the time of the call; if it doesn't
159*635a8641SAndroid Build Coastguard Worker // match |original| then the swap didn't happen so loop again.
160*635a8641SAndroid Build Coastguard Worker subtle::Atomic32 existing = subtle::Release_CompareAndSwap(
161*635a8641SAndroid Build Coastguard Worker &as_atomic, original, single_sample.as_atomic);
162*635a8641SAndroid Build Coastguard Worker sample_updated = (existing == original);
163*635a8641SAndroid Build Coastguard Worker } while (!sample_updated);
164*635a8641SAndroid Build Coastguard Worker
165*635a8641SAndroid Build Coastguard Worker return true;
166*635a8641SAndroid Build Coastguard Worker }
167*635a8641SAndroid Build Coastguard Worker
IsDisabled() const168*635a8641SAndroid Build Coastguard Worker bool HistogramSamples::AtomicSingleSample::IsDisabled() const {
169*635a8641SAndroid Build Coastguard Worker return subtle::Acquire_Load(&as_atomic) == kDisabledSingleSample;
170*635a8641SAndroid Build Coastguard Worker }
171*635a8641SAndroid Build Coastguard Worker
LocalMetadata()172*635a8641SAndroid Build Coastguard Worker HistogramSamples::LocalMetadata::LocalMetadata() {
173*635a8641SAndroid Build Coastguard Worker // This is the same way it's done for persistent metadata since no ctor
174*635a8641SAndroid Build Coastguard Worker // is called for the data members in that case.
175*635a8641SAndroid Build Coastguard Worker memset(this, 0, sizeof(*this));
176*635a8641SAndroid Build Coastguard Worker }
177*635a8641SAndroid Build Coastguard Worker
HistogramSamples(uint64_t id,Metadata * meta)178*635a8641SAndroid Build Coastguard Worker HistogramSamples::HistogramSamples(uint64_t id, Metadata* meta)
179*635a8641SAndroid Build Coastguard Worker : meta_(meta) {
180*635a8641SAndroid Build Coastguard Worker DCHECK(meta_->id == 0 || meta_->id == id);
181*635a8641SAndroid Build Coastguard Worker
182*635a8641SAndroid Build Coastguard Worker // It's possible that |meta| is contained in initialized, read-only memory
183*635a8641SAndroid Build Coastguard Worker // so it's essential that no write be done in that case.
184*635a8641SAndroid Build Coastguard Worker if (!meta_->id)
185*635a8641SAndroid Build Coastguard Worker meta_->id = id;
186*635a8641SAndroid Build Coastguard Worker }
187*635a8641SAndroid Build Coastguard Worker
188*635a8641SAndroid Build Coastguard Worker // This mustn't do anything with |meta_|. It was passed to the ctor and may
189*635a8641SAndroid Build Coastguard Worker // be invalid by the time this dtor gets called.
190*635a8641SAndroid Build Coastguard Worker HistogramSamples::~HistogramSamples() = default;
191*635a8641SAndroid Build Coastguard Worker
Add(const HistogramSamples & other)192*635a8641SAndroid Build Coastguard Worker void HistogramSamples::Add(const HistogramSamples& other) {
193*635a8641SAndroid Build Coastguard Worker IncreaseSumAndCount(other.sum(), other.redundant_count());
194*635a8641SAndroid Build Coastguard Worker std::unique_ptr<SampleCountIterator> it = other.Iterator();
195*635a8641SAndroid Build Coastguard Worker bool success = AddSubtractImpl(it.get(), ADD);
196*635a8641SAndroid Build Coastguard Worker DCHECK(success);
197*635a8641SAndroid Build Coastguard Worker }
198*635a8641SAndroid Build Coastguard Worker
AddFromPickle(PickleIterator * iter)199*635a8641SAndroid Build Coastguard Worker bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
200*635a8641SAndroid Build Coastguard Worker int64_t sum;
201*635a8641SAndroid Build Coastguard Worker HistogramBase::Count redundant_count;
202*635a8641SAndroid Build Coastguard Worker
203*635a8641SAndroid Build Coastguard Worker if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count))
204*635a8641SAndroid Build Coastguard Worker return false;
205*635a8641SAndroid Build Coastguard Worker
206*635a8641SAndroid Build Coastguard Worker IncreaseSumAndCount(sum, redundant_count);
207*635a8641SAndroid Build Coastguard Worker
208*635a8641SAndroid Build Coastguard Worker SampleCountPickleIterator pickle_iter(iter);
209*635a8641SAndroid Build Coastguard Worker return AddSubtractImpl(&pickle_iter, ADD);
210*635a8641SAndroid Build Coastguard Worker }
211*635a8641SAndroid Build Coastguard Worker
Subtract(const HistogramSamples & other)212*635a8641SAndroid Build Coastguard Worker void HistogramSamples::Subtract(const HistogramSamples& other) {
213*635a8641SAndroid Build Coastguard Worker IncreaseSumAndCount(-other.sum(), -other.redundant_count());
214*635a8641SAndroid Build Coastguard Worker std::unique_ptr<SampleCountIterator> it = other.Iterator();
215*635a8641SAndroid Build Coastguard Worker bool success = AddSubtractImpl(it.get(), SUBTRACT);
216*635a8641SAndroid Build Coastguard Worker DCHECK(success);
217*635a8641SAndroid Build Coastguard Worker }
218*635a8641SAndroid Build Coastguard Worker
Serialize(Pickle * pickle) const219*635a8641SAndroid Build Coastguard Worker void HistogramSamples::Serialize(Pickle* pickle) const {
220*635a8641SAndroid Build Coastguard Worker pickle->WriteInt64(sum());
221*635a8641SAndroid Build Coastguard Worker pickle->WriteInt(redundant_count());
222*635a8641SAndroid Build Coastguard Worker
223*635a8641SAndroid Build Coastguard Worker HistogramBase::Sample min;
224*635a8641SAndroid Build Coastguard Worker int64_t max;
225*635a8641SAndroid Build Coastguard Worker HistogramBase::Count count;
226*635a8641SAndroid Build Coastguard Worker for (std::unique_ptr<SampleCountIterator> it = Iterator(); !it->Done();
227*635a8641SAndroid Build Coastguard Worker it->Next()) {
228*635a8641SAndroid Build Coastguard Worker it->Get(&min, &max, &count);
229*635a8641SAndroid Build Coastguard Worker pickle->WriteInt(min);
230*635a8641SAndroid Build Coastguard Worker pickle->WriteInt64(max);
231*635a8641SAndroid Build Coastguard Worker pickle->WriteInt(count);
232*635a8641SAndroid Build Coastguard Worker }
233*635a8641SAndroid Build Coastguard Worker }
234*635a8641SAndroid Build Coastguard Worker
AccumulateSingleSample(HistogramBase::Sample value,HistogramBase::Count count,size_t bucket)235*635a8641SAndroid Build Coastguard Worker bool HistogramSamples::AccumulateSingleSample(HistogramBase::Sample value,
236*635a8641SAndroid Build Coastguard Worker HistogramBase::Count count,
237*635a8641SAndroid Build Coastguard Worker size_t bucket) {
238*635a8641SAndroid Build Coastguard Worker if (single_sample().Accumulate(bucket, count)) {
239*635a8641SAndroid Build Coastguard Worker // Success. Update the (separate) sum and redundant-count.
240*635a8641SAndroid Build Coastguard Worker IncreaseSumAndCount(strict_cast<int64_t>(value) * count, count);
241*635a8641SAndroid Build Coastguard Worker return true;
242*635a8641SAndroid Build Coastguard Worker }
243*635a8641SAndroid Build Coastguard Worker return false;
244*635a8641SAndroid Build Coastguard Worker }
245*635a8641SAndroid Build Coastguard Worker
IncreaseSumAndCount(int64_t sum,HistogramBase::Count count)246*635a8641SAndroid Build Coastguard Worker void HistogramSamples::IncreaseSumAndCount(int64_t sum,
247*635a8641SAndroid Build Coastguard Worker HistogramBase::Count count) {
248*635a8641SAndroid Build Coastguard Worker #ifdef ARCH_CPU_64_BITS
249*635a8641SAndroid Build Coastguard Worker subtle::NoBarrier_AtomicIncrement(&meta_->sum, sum);
250*635a8641SAndroid Build Coastguard Worker #else
251*635a8641SAndroid Build Coastguard Worker meta_->sum += sum;
252*635a8641SAndroid Build Coastguard Worker #endif
253*635a8641SAndroid Build Coastguard Worker subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count, count);
254*635a8641SAndroid Build Coastguard Worker }
255*635a8641SAndroid Build Coastguard Worker
RecordNegativeSample(NegativeSampleReason reason,HistogramBase::Count increment)256*635a8641SAndroid Build Coastguard Worker void HistogramSamples::RecordNegativeSample(NegativeSampleReason reason,
257*635a8641SAndroid Build Coastguard Worker HistogramBase::Count increment) {
258*635a8641SAndroid Build Coastguard Worker UMA_HISTOGRAM_ENUMERATION("UMA.NegativeSamples.Reason", reason,
259*635a8641SAndroid Build Coastguard Worker MAX_NEGATIVE_SAMPLE_REASONS);
260*635a8641SAndroid Build Coastguard Worker UMA_HISTOGRAM_CUSTOM_COUNTS("UMA.NegativeSamples.Increment", increment, 1,
261*635a8641SAndroid Build Coastguard Worker 1 << 30, 100);
262*635a8641SAndroid Build Coastguard Worker UmaHistogramSparse("UMA.NegativeSamples.Histogram",
263*635a8641SAndroid Build Coastguard Worker static_cast<int32_t>(id()));
264*635a8641SAndroid Build Coastguard Worker }
265*635a8641SAndroid Build Coastguard Worker
266*635a8641SAndroid Build Coastguard Worker SampleCountIterator::~SampleCountIterator() = default;
267*635a8641SAndroid Build Coastguard Worker
GetBucketIndex(size_t * index) const268*635a8641SAndroid Build Coastguard Worker bool SampleCountIterator::GetBucketIndex(size_t* index) const {
269*635a8641SAndroid Build Coastguard Worker DCHECK(!Done());
270*635a8641SAndroid Build Coastguard Worker return false;
271*635a8641SAndroid Build Coastguard Worker }
272*635a8641SAndroid Build Coastguard Worker
SingleSampleIterator(HistogramBase::Sample min,int64_t max,HistogramBase::Count count)273*635a8641SAndroid Build Coastguard Worker SingleSampleIterator::SingleSampleIterator(HistogramBase::Sample min,
274*635a8641SAndroid Build Coastguard Worker int64_t max,
275*635a8641SAndroid Build Coastguard Worker HistogramBase::Count count)
276*635a8641SAndroid Build Coastguard Worker : SingleSampleIterator(min, max, count, kSizeMax) {}
277*635a8641SAndroid Build Coastguard Worker
SingleSampleIterator(HistogramBase::Sample min,int64_t max,HistogramBase::Count count,size_t bucket_index)278*635a8641SAndroid Build Coastguard Worker SingleSampleIterator::SingleSampleIterator(HistogramBase::Sample min,
279*635a8641SAndroid Build Coastguard Worker int64_t max,
280*635a8641SAndroid Build Coastguard Worker HistogramBase::Count count,
281*635a8641SAndroid Build Coastguard Worker size_t bucket_index)
282*635a8641SAndroid Build Coastguard Worker : min_(min), max_(max), bucket_index_(bucket_index), count_(count) {}
283*635a8641SAndroid Build Coastguard Worker
284*635a8641SAndroid Build Coastguard Worker SingleSampleIterator::~SingleSampleIterator() = default;
285*635a8641SAndroid Build Coastguard Worker
Done() const286*635a8641SAndroid Build Coastguard Worker bool SingleSampleIterator::Done() const {
287*635a8641SAndroid Build Coastguard Worker return count_ == 0;
288*635a8641SAndroid Build Coastguard Worker }
289*635a8641SAndroid Build Coastguard Worker
Next()290*635a8641SAndroid Build Coastguard Worker void SingleSampleIterator::Next() {
291*635a8641SAndroid Build Coastguard Worker DCHECK(!Done());
292*635a8641SAndroid Build Coastguard Worker count_ = 0;
293*635a8641SAndroid Build Coastguard Worker }
294*635a8641SAndroid Build Coastguard Worker
Get(HistogramBase::Sample * min,int64_t * max,HistogramBase::Count * count) const295*635a8641SAndroid Build Coastguard Worker void SingleSampleIterator::Get(HistogramBase::Sample* min,
296*635a8641SAndroid Build Coastguard Worker int64_t* max,
297*635a8641SAndroid Build Coastguard Worker HistogramBase::Count* count) const {
298*635a8641SAndroid Build Coastguard Worker DCHECK(!Done());
299*635a8641SAndroid Build Coastguard Worker if (min != nullptr)
300*635a8641SAndroid Build Coastguard Worker *min = min_;
301*635a8641SAndroid Build Coastguard Worker if (max != nullptr)
302*635a8641SAndroid Build Coastguard Worker *max = max_;
303*635a8641SAndroid Build Coastguard Worker if (count != nullptr)
304*635a8641SAndroid Build Coastguard Worker *count = count_;
305*635a8641SAndroid Build Coastguard Worker }
306*635a8641SAndroid Build Coastguard Worker
GetBucketIndex(size_t * index) const307*635a8641SAndroid Build Coastguard Worker bool SingleSampleIterator::GetBucketIndex(size_t* index) const {
308*635a8641SAndroid Build Coastguard Worker DCHECK(!Done());
309*635a8641SAndroid Build Coastguard Worker if (bucket_index_ == kSizeMax)
310*635a8641SAndroid Build Coastguard Worker return false;
311*635a8641SAndroid Build Coastguard Worker *index = bucket_index_;
312*635a8641SAndroid Build Coastguard Worker return true;
313*635a8641SAndroid Build Coastguard Worker }
314*635a8641SAndroid Build Coastguard Worker
315*635a8641SAndroid Build Coastguard Worker } // namespace base
316