xref: /aosp_15_r20/external/libchrome/base/metrics/histogram_samples.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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