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"
12 typedef HistogramBase::Count Count
;
13 typedef HistogramBase::Sample Sample
;
15 SampleVector::SampleVector(const BucketRanges
* bucket_ranges
)
16 : counts_(bucket_ranges
->bucket_count()),
17 bucket_ranges_(bucket_ranges
) {
18 CHECK_GE(bucket_ranges_
->bucket_count(), 1u);
21 SampleVector::~SampleVector() {}
23 void SampleVector::Accumulate(Sample value
, Count count
) {
24 size_t bucket_index
= GetBucketIndex(value
);
25 subtle::NoBarrier_Store(&counts_
[bucket_index
],
26 subtle::NoBarrier_Load(&counts_
[bucket_index
]) + count
);
27 IncreaseSum(count
* value
);
28 IncreaseRedundantCount(count
);
31 Count
SampleVector::GetCount(Sample value
) const {
32 size_t bucket_index
= GetBucketIndex(value
);
33 return subtle::NoBarrier_Load(&counts_
[bucket_index
]);
36 Count
SampleVector::TotalCount() const {
38 for (size_t i
= 0; i
< counts_
.size(); i
++) {
39 count
+= subtle::NoBarrier_Load(&counts_
[i
]);
44 Count
SampleVector::GetCountAtIndex(size_t bucket_index
) const {
45 DCHECK(bucket_index
< counts_
.size());
46 return subtle::NoBarrier_Load(&counts_
[bucket_index
]);
49 scoped_ptr
<SampleCountIterator
> SampleVector::Iterator() const {
50 return scoped_ptr
<SampleCountIterator
>(
51 new SampleVectorIterator(&counts_
, bucket_ranges_
));
54 bool SampleVector::AddSubtractImpl(SampleCountIterator
* iter
,
55 HistogramSamples::Operator op
) {
56 HistogramBase::Sample min
;
57 HistogramBase::Sample max
;
58 HistogramBase::Count count
;
60 // Go through the iterator and add the counts into correct bucket.
62 while (index
< counts_
.size() && !iter
->Done()) {
63 iter
->Get(&min
, &max
, &count
);
64 if (min
== bucket_ranges_
->range(index
) &&
65 max
== bucket_ranges_
->range(index
+ 1)) {
66 // Sample matches this bucket!
67 HistogramBase::Count old_counts
=
68 subtle::NoBarrier_Load(&counts_
[index
]);
69 subtle::NoBarrier_Store(&counts_
[index
],
70 old_counts
+ ((op
== HistogramSamples::ADD
) ? count
: -count
));
72 } else if (min
> bucket_ranges_
->range(index
)) {
73 // Sample is larger than current bucket range. Try next.
76 // Sample is smaller than current bucket range. We scan buckets from
77 // smallest to largest, so the sample value must be invalid.
85 // Use simple binary search. This is very general, but there are better
86 // approaches if we knew that the buckets were linearly distributed.
87 size_t SampleVector::GetBucketIndex(Sample value
) const {
88 size_t bucket_count
= bucket_ranges_
->bucket_count();
89 CHECK_GE(bucket_count
, 1u);
90 CHECK_GE(value
, bucket_ranges_
->range(0));
91 CHECK_LT(value
, bucket_ranges_
->range(bucket_count
));
94 size_t over
= bucket_count
;
97 DCHECK_GE(over
, under
);
98 mid
= under
+ (over
- under
)/2;
101 if (bucket_ranges_
->range(mid
) <= value
)
107 DCHECK_LE(bucket_ranges_
->range(mid
), value
);
108 CHECK_GT(bucket_ranges_
->range(mid
+ 1), value
);
112 SampleVectorIterator::SampleVectorIterator(const std::vector
<Count
>* counts
,
113 const BucketRanges
* bucket_ranges
)
115 bucket_ranges_(bucket_ranges
),
117 CHECK_GE(bucket_ranges_
->bucket_count(), counts_
->size());
121 SampleVectorIterator::~SampleVectorIterator() {}
123 bool SampleVectorIterator::Done() const {
124 return index_
>= counts_
->size();
127 void SampleVectorIterator::Next() {
133 void SampleVectorIterator::Get(HistogramBase::Sample
* min
,
134 HistogramBase::Sample
* max
,
135 HistogramBase::Count
* count
) const {
138 *min
= bucket_ranges_
->range(index_
);
140 *max
= bucket_ranges_
->range(index_
+ 1);
142 *count
= subtle::NoBarrier_Load(&(*counts_
)[index_
]);
145 bool SampleVectorIterator::GetBucketIndex(size_t* index
) const {
152 void SampleVectorIterator::SkipEmptyBuckets() {
156 while (index_
< counts_
->size()) {
157 if (subtle::NoBarrier_Load(&(*counts_
)[index_
]) != 0)