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 subtle::NoBarrier_Load(&counts_
[bucket_index
]);
38 Count
SampleVector::TotalCount() const {
40 for (size_t i
= 0; i
< counts_
.size(); i
++) {
41 count
+= subtle::NoBarrier_Load(&counts_
[i
]);
46 Count
SampleVector::GetCountAtIndex(size_t bucket_index
) const {
47 DCHECK(bucket_index
< counts_
.size());
48 return subtle::NoBarrier_Load(&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 HistogramBase::Count old_counts
=
70 subtle::NoBarrier_Load(&counts_
[index
]);
71 subtle::NoBarrier_Store(&counts_
[index
],
72 old_counts
+ ((op
== HistogramSamples::ADD
) ? count
: -count
));
74 } else if (min
> bucket_ranges_
->range(index
)) {
75 // Sample is larger than current bucket range. Try next.
78 // Sample is smaller than current bucket range. We scan buckets from
79 // smallest to largest, so the sample value must be invalid.
87 // Use simple binary search. This is very general, but there are better
88 // approaches if we knew that the buckets were linearly distributed.
89 size_t SampleVector::GetBucketIndex(Sample value
) const {
90 size_t bucket_count
= bucket_ranges_
->bucket_count();
91 CHECK_GE(bucket_count
, 1u);
92 CHECK_GE(value
, bucket_ranges_
->range(0));
93 CHECK_LT(value
, bucket_ranges_
->range(bucket_count
));
96 size_t over
= bucket_count
;
99 DCHECK_GE(over
, under
);
100 mid
= under
+ (over
- under
)/2;
103 if (bucket_ranges_
->range(mid
) <= value
)
109 DCHECK_LE(bucket_ranges_
->range(mid
), value
);
110 CHECK_GT(bucket_ranges_
->range(mid
+ 1), value
);
114 SampleVectorIterator::SampleVectorIterator(const vector
<Count
>* counts
,
115 const BucketRanges
* bucket_ranges
)
117 bucket_ranges_(bucket_ranges
),
119 CHECK_GE(bucket_ranges_
->bucket_count(), counts_
->size());
123 SampleVectorIterator::~SampleVectorIterator() {}
125 bool SampleVectorIterator::Done() const {
126 return index_
>= counts_
->size();
129 void SampleVectorIterator::Next() {
135 void SampleVectorIterator::Get(HistogramBase::Sample
* min
,
136 HistogramBase::Sample
* max
,
137 HistogramBase::Count
* count
) const {
140 *min
= bucket_ranges_
->range(index_
);
142 *max
= bucket_ranges_
->range(index_
+ 1);
144 *count
= subtle::NoBarrier_Load(&(*counts_
)[index_
]);
147 bool SampleVectorIterator::GetBucketIndex(size_t* index
) const {
154 void SampleVectorIterator::SkipEmptyBuckets() {
158 while (index_
< counts_
->size()) {
159 if (subtle::NoBarrier_Load(&(*counts_
)[index_
]) != 0)