• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "base/metrics/sample_vector.h"
6 
7 #include "base/logging.h"
8 #include "base/metrics/bucket_ranges.h"
9 
10 namespace base {
11 
12 typedef HistogramBase::Count Count;
13 typedef HistogramBase::Sample Sample;
14 
SampleVector(const BucketRanges * bucket_ranges)15 SampleVector::SampleVector(const BucketRanges* bucket_ranges)
16     : SampleVector(0, bucket_ranges) {}
17 
SampleVector(uint64_t id,const BucketRanges * bucket_ranges)18 SampleVector::SampleVector(uint64_t id, const BucketRanges* bucket_ranges)
19     : HistogramSamples(id),
20       local_counts_(bucket_ranges->bucket_count()),
21       counts_(&local_counts_[0]),
22       counts_size_(local_counts_.size()),
23       bucket_ranges_(bucket_ranges) {
24   CHECK_GE(bucket_ranges_->bucket_count(), 1u);
25 }
26 
SampleVector(uint64_t id,HistogramBase::AtomicCount * counts,size_t,Metadata * meta,const BucketRanges * bucket_ranges)27 SampleVector::SampleVector(uint64_t id,
28                            HistogramBase::AtomicCount* counts,
29                            size_t /*counts_size*/,
30                            Metadata* meta,
31                            const BucketRanges* bucket_ranges)
32     : HistogramSamples(id, meta),
33       counts_(counts),
34       counts_size_(bucket_ranges->bucket_count()),
35       bucket_ranges_(bucket_ranges) {
36   CHECK_LE(bucket_ranges_->bucket_count(), counts_size_);
37   CHECK_GE(bucket_ranges_->bucket_count(), 1u);
38 }
39 
~SampleVector()40 SampleVector::~SampleVector() {}
41 
Accumulate(Sample value,Count count)42 void SampleVector::Accumulate(Sample value, Count count) {
43   size_t bucket_index = GetBucketIndex(value);
44   subtle::NoBarrier_AtomicIncrement(&counts_[bucket_index], count);
45   IncreaseSum(static_cast<int64_t>(count) * value);
46   IncreaseRedundantCount(count);
47 }
48 
GetCount(Sample value) const49 Count SampleVector::GetCount(Sample value) const {
50   size_t bucket_index = GetBucketIndex(value);
51   return subtle::NoBarrier_Load(&counts_[bucket_index]);
52 }
53 
TotalCount() const54 Count SampleVector::TotalCount() const {
55   Count count = 0;
56   for (size_t i = 0; i < counts_size_; i++) {
57     count += subtle::NoBarrier_Load(&counts_[i]);
58   }
59   return count;
60 }
61 
GetCountAtIndex(size_t bucket_index) const62 Count SampleVector::GetCountAtIndex(size_t bucket_index) const {
63   DCHECK(bucket_index < counts_size_);
64   return subtle::NoBarrier_Load(&counts_[bucket_index]);
65 }
66 
Iterator() const67 std::unique_ptr<SampleCountIterator> SampleVector::Iterator() const {
68   return std::unique_ptr<SampleCountIterator>(
69       new SampleVectorIterator(counts_, counts_size_, bucket_ranges_));
70 }
71 
AddSubtractImpl(SampleCountIterator * iter,HistogramSamples::Operator op)72 bool SampleVector::AddSubtractImpl(SampleCountIterator* iter,
73                                    HistogramSamples::Operator op) {
74   HistogramBase::Sample min;
75   HistogramBase::Sample max;
76   HistogramBase::Count count;
77 
78   // Go through the iterator and add the counts into correct bucket.
79   size_t index = 0;
80   while (index < counts_size_ && !iter->Done()) {
81     iter->Get(&min, &max, &count);
82     if (min == bucket_ranges_->range(index) &&
83         max == bucket_ranges_->range(index + 1)) {
84       // Sample matches this bucket!
85       subtle::NoBarrier_AtomicIncrement(
86           &counts_[index], op == HistogramSamples::ADD ? count : -count);
87       iter->Next();
88     } else if (min > bucket_ranges_->range(index)) {
89       // Sample is larger than current bucket range. Try next.
90       index++;
91     } else {
92       // Sample is smaller than current bucket range. We scan buckets from
93       // smallest to largest, so the sample value must be invalid.
94       return false;
95     }
96   }
97 
98   return iter->Done();
99 }
100 
101 // Use simple binary search.  This is very general, but there are better
102 // approaches if we knew that the buckets were linearly distributed.
GetBucketIndex(Sample value) const103 size_t SampleVector::GetBucketIndex(Sample value) const {
104   size_t bucket_count = bucket_ranges_->bucket_count();
105   CHECK_GE(bucket_count, 1u);
106   CHECK_GE(value, bucket_ranges_->range(0));
107   CHECK_LT(value, bucket_ranges_->range(bucket_count));
108 
109   size_t under = 0;
110   size_t over = bucket_count;
111   size_t mid;
112   do {
113     DCHECK_GE(over, under);
114     mid = under + (over - under)/2;
115     if (mid == under)
116       break;
117     if (bucket_ranges_->range(mid) <= value)
118       under = mid;
119     else
120       over = mid;
121   } while (true);
122 
123   DCHECK_LE(bucket_ranges_->range(mid), value);
124   CHECK_GT(bucket_ranges_->range(mid + 1), value);
125   return mid;
126 }
127 
SampleVectorIterator(const std::vector<HistogramBase::AtomicCount> * counts,const BucketRanges * bucket_ranges)128 SampleVectorIterator::SampleVectorIterator(
129     const std::vector<HistogramBase::AtomicCount>* counts,
130     const BucketRanges* bucket_ranges)
131     : counts_(&(*counts)[0]),
132       counts_size_(counts->size()),
133       bucket_ranges_(bucket_ranges),
134       index_(0) {
135   CHECK_GE(bucket_ranges_->bucket_count(), counts_size_);
136   SkipEmptyBuckets();
137 }
138 
SampleVectorIterator(const HistogramBase::AtomicCount * counts,size_t counts_size,const BucketRanges * bucket_ranges)139 SampleVectorIterator::SampleVectorIterator(
140     const HistogramBase::AtomicCount* counts,
141     size_t counts_size,
142     const BucketRanges* bucket_ranges)
143     : counts_(counts),
144       counts_size_(counts_size),
145       bucket_ranges_(bucket_ranges),
146       index_(0) {
147   CHECK_GE(bucket_ranges_->bucket_count(), counts_size_);
148   SkipEmptyBuckets();
149 }
150 
~SampleVectorIterator()151 SampleVectorIterator::~SampleVectorIterator() {}
152 
Done() const153 bool SampleVectorIterator::Done() const {
154   return index_ >= counts_size_;
155 }
156 
Next()157 void SampleVectorIterator::Next() {
158   DCHECK(!Done());
159   index_++;
160   SkipEmptyBuckets();
161 }
162 
Get(HistogramBase::Sample * min,HistogramBase::Sample * max,HistogramBase::Count * count) const163 void SampleVectorIterator::Get(HistogramBase::Sample* min,
164                                HistogramBase::Sample* max,
165                                HistogramBase::Count* count) const {
166   DCHECK(!Done());
167   if (min != NULL)
168     *min = bucket_ranges_->range(index_);
169   if (max != NULL)
170     *max = bucket_ranges_->range(index_ + 1);
171   if (count != NULL)
172     *count = subtle::NoBarrier_Load(&counts_[index_]);
173 }
174 
GetBucketIndex(size_t * index) const175 bool SampleVectorIterator::GetBucketIndex(size_t* index) const {
176   DCHECK(!Done());
177   if (index != NULL)
178     *index = index_;
179   return true;
180 }
181 
SkipEmptyBuckets()182 void SampleVectorIterator::SkipEmptyBuckets() {
183   if (Done())
184     return;
185 
186   while (index_ < counts_size_) {
187     if (subtle::NoBarrier_Load(&counts_[index_]) != 0)
188       return;
189     index_++;
190   }
191 }
192 
193 }  // namespace base
194