|
OLD | NEW |
---|---|
(Empty) | |
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 using std::vector; | |
11 | |
12 namespace base { | |
13 | |
14 typedef HistogramBase::Count Count; | |
15 typedef HistogramBase::Sample Sample; | |
16 | |
17 SampleVector::SampleVector(const BucketRanges* bucket_ranges) | |
18 : counts_(bucket_ranges->size() - 1), | |
19 bucket_ranges_(bucket_ranges) { | |
20 CHECK_GE(bucket_ranges_->size(), 2u); | |
21 } | |
22 | |
23 SampleVector::~SampleVector() {} | |
24 | |
25 void SampleVector::Accumulate(Sample value, Count count) { | |
26 size_t bucket_index = GetBucketIndex(value); | |
27 counts_[bucket_index] += count; | |
28 IncreaseSum(count * value); | |
29 IncreaseRedundantCount(count); | |
30 } | |
31 | |
32 Count SampleVector::GetCount(Sample value) const { | |
33 size_t bucket_index = GetBucketIndex(value); | |
34 return counts_[bucket_index]; | |
35 } | |
36 | |
37 Count SampleVector::TotalCount() const { | |
38 Count count = 0; | |
39 for (size_t i = 0; i < counts_.size(); i++) { | |
40 count += counts_[i]; | |
41 } | |
42 return count; | |
43 } | |
44 | |
45 Count SampleVector::GetCountAtIndex(size_t bucket_index) const { | |
46 DCHECK(bucket_index >= 0 && bucket_index < counts_.size()); | |
47 return counts_[bucket_index]; | |
48 } | |
49 | |
50 scoped_ptr<SampleCountIterator> SampleVector::Iterator() const { | |
51 return scoped_ptr<SampleCountIterator>( | |
52 new SampleVectorIterator(&counts_, bucket_ranges_)); | |
53 } | |
54 | |
55 bool SampleVector::AddSubtractImpl(SampleCountIterator* iter, | |
56 HistogramSamples::Instruction instruction) { | |
57 HistogramBase::Sample min; | |
58 HistogramBase::Sample max; | |
59 HistogramBase::Count count; | |
60 | |
61 // Go through the iterator and add the counts into correct bucket. | |
62 size_t index = 0; | |
63 while (index < counts_.size() && !iter->Done()) { | |
64 iter->Get(&min, &max, &count); | |
65 if (min == bucket_ranges_->range(index) && | |
66 max == bucket_ranges_->range(index + 1)) { | |
67 // Sample matches this bucket! | |
68 counts_[index] += | |
69 (instruction == HistogramSamples::ADD) ? count : -count; | |
70 iter->Next(); | |
71 } else if (min > bucket_ranges_->range(index)) { | |
72 // Sample is larger than current bucket range. Try next. | |
73 index++; | |
74 } else { | |
75 // Sample is smaller than current bucket range. We scan buckets from | |
76 // smallest to largest, so the sample value must be invalid. | |
77 return false; | |
78 } | |
79 } | |
80 | |
81 return iter->Done(); | |
82 } | |
83 | |
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_->size() - 1; | |
88 CHECK_GE(bucket_count, 1u); | |
89 CHECK_GE(value, bucket_ranges_->range(0)); | |
90 CHECK_LT(value, bucket_ranges_->range(bucket_count)); | |
91 | |
92 size_t under = 0; | |
93 size_t over = bucket_count; | |
94 size_t mid; | |
95 do { | |
96 DCHECK_GE(over, under); | |
97 mid = under + (over - under)/2; | |
98 if (mid == under) | |
99 break; | |
100 if (bucket_ranges_->range(mid) <= value) | |
101 under = mid; | |
102 else | |
103 over = mid; | |
104 } while (true); | |
105 | |
106 DCHECK_LE(bucket_ranges_->range(mid), value); | |
107 CHECK_GT(bucket_ranges_->range(mid + 1), value); | |
108 return mid; | |
109 } | |
110 | |
111 SampleVectorIterator::SampleVectorIterator(const vector<Count>* counts, | |
112 const BucketRanges* bucket_ranges) | |
113 : counts_(counts), | |
114 bucket_ranges_(bucket_ranges), | |
115 index_(0) { | |
116 CHECK_GT(bucket_ranges_->size(), counts_->size()); | |
117 SkipEmptyBuckets(); | |
118 } | |
119 | |
120 bool SampleVectorIterator::Done() const { | |
121 return index_ >= counts_->size(); | |
122 } | |
123 | |
124 void SampleVectorIterator::Next() { | |
125 CHECK(!Done()); | |
Ilya Sherman
2012/09/21 08:52:12
nit: DCHECK
kaiwang
2012/09/21 19:51:18
Done.
| |
126 index_++; | |
127 SkipEmptyBuckets(); | |
128 } | |
129 | |
130 void SampleVectorIterator::Get(HistogramBase::Sample* min, | |
131 HistogramBase::Sample* max, | |
132 HistogramBase::Count* count) const { | |
133 CHECK(!Done()); | |
Ilya Sherman
2012/09/21 08:52:12
nit: DCHECK
kaiwang
2012/09/21 19:51:18
Done.
| |
134 if (min != NULL) | |
135 *min = bucket_ranges_->range(index_); | |
136 if (max != NULL) | |
137 *max = bucket_ranges_->range(index_ + 1); | |
138 if (count != NULL) | |
139 *count = (*counts_)[index_]; | |
140 } | |
141 | |
142 bool SampleVectorIterator::GetBucketIndex(size_t* index) const { | |
143 CHECK(!Done()); | |
Ilya Sherman
2012/09/21 08:52:12
nit: DCHECK
kaiwang
2012/09/21 19:51:18
Done.
| |
144 if (index != NULL) | |
145 *index = index_; | |
146 return true; | |
147 } | |
148 | |
149 void SampleVectorIterator::SkipEmptyBuckets() { | |
150 if (Done()) | |
151 return; | |
152 | |
153 while (index_ < counts_->size()) { | |
154 if ((*counts_)[index_] != 0) | |
155 return; | |
156 index_++; | |
157 } | |
158 } | |
159 | |
160 } // namespace base | |
OLD | NEW |