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.
5 #include "base/metrics/sample_vector.h"
7 #include "base/logging.h"
8 #include "base/metrics/bucket_ranges.h"
14 typedef HistogramBase::Count Count
;
15 typedef HistogramBase::Sample Sample
;
17 SampleVector::SampleVector(const BucketRanges
* bucket_ranges
)
18 : counts_(bucket_ranges
->bucket_count()),
19 bucket_ranges_(bucket_ranges
) {
20 CHECK_GE(bucket_ranges_
->bucket_count(), 1u);
23 SampleVector::~SampleVector() {}
25 void SampleVector::Accumulate(Sample value
, Count count
) {
26 size_t bucket_index
= GetBucketIndex(value
);
27 subtle::NoBarrier_Store(&counts_
[bucket_index
],
28 subtle::NoBarrier_Load(&counts_
[bucket_index
]) + count
);
29 IncreaseSum(count
* value
);
30 IncreaseRedundantCount(count
);
33 Count
SampleVector::GetCount(Sample value
) const {
34 size_t bucket_index
= GetBucketIndex(value
);
35 return counts_
[bucket_index
];
38 Count
SampleVector::TotalCount() const {
40 for (size_t i
= 0; i
< counts_
.size(); i
++) {
46 Count
SampleVector::GetCountAtIndex(size_t bucket_index
) const {
47 DCHECK(bucket_index
< counts_
.size());
48 return counts_
[bucket_index
];
51 scoped_ptr
<SampleCountIterator
> SampleVector::Iterator() const {
52 return scoped_ptr
<SampleCountIterator
>(
53 new SampleVectorIterator(&counts_
, bucket_ranges_
));
56 bool SampleVector::AddSubtractImpl(SampleCountIterator
* iter
,
57 HistogramSamples::Operator op
) {
58 HistogramBase::Sample min
;
59 HistogramBase::Sample max
;
60 HistogramBase::Count count
;
62 // Go through the iterator and add the counts into correct bucket.
64 while (index
< counts_
.size() && !iter
->Done()) {
65 iter
->Get(&min
, &max
, &count
);
66 if (min
== bucket_ranges_
->range(index
) &&
67 max
== bucket_ranges_
->range(index
+ 1)) {
68 // Sample matches this bucket!
69 counts_
[index
] += (op
== HistogramSamples::ADD
) ? count
: -count
;
71 } else if (min
> bucket_ranges_
->range(index
)) {
72 // Sample is larger than current bucket range. Try next.
75 // Sample is smaller than current bucket range. We scan buckets from
76 // smallest to largest, so the sample value must be invalid.
84 // Use simple binary search. This is very general, but there are better
85 // approaches if we knew that the buckets were linearly distributed.
86 size_t SampleVector::GetBucketIndex(Sample value
) const {
87 size_t bucket_count
= bucket_ranges_
->bucket_count();
88 CHECK_GE(bucket_count
, 1u);
89 CHECK_GE(value
, bucket_ranges_
->range(0));
90 CHECK_LT(value
, bucket_ranges_
->range(bucket_count
));
93 size_t over
= bucket_count
;
96 DCHECK_GE(over
, under
);
97 mid
= under
+ (over
- under
)/2;
100 if (bucket_ranges_
->range(mid
) <= value
)
106 DCHECK_LE(bucket_ranges_
->range(mid
), value
);
107 CHECK_GT(bucket_ranges_
->range(mid
+ 1), value
);
111 SampleVectorIterator::SampleVectorIterator(const vector
<Count
>* counts
,
112 const BucketRanges
* bucket_ranges
)
114 bucket_ranges_(bucket_ranges
),
116 CHECK_GE(bucket_ranges_
->bucket_count(), counts_
->size());
120 SampleVectorIterator::~SampleVectorIterator() {}
122 bool SampleVectorIterator::Done() const {
123 return index_
>= counts_
->size();
126 void SampleVectorIterator::Next() {
132 void SampleVectorIterator::Get(HistogramBase::Sample
* min
,
133 HistogramBase::Sample
* max
,
134 HistogramBase::Count
* count
) const {
137 *min
= bucket_ranges_
->range(index_
);
139 *max
= bucket_ranges_
->range(index_
+ 1);
141 *count
= (*counts_
)[index_
];
144 bool SampleVectorIterator::GetBucketIndex(size_t* index
) const {
151 void SampleVectorIterator::SkipEmptyBuckets() {
155 while (index_
< counts_
->size()) {
156 if ((*counts_
)[index_
] != 0)