1 | /* |
2 | * Copyright 2013-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <folly/Conv.h> |
20 | #include <folly/stats/BucketedTimeSeries-defs.h> |
21 | #include <folly/stats/Histogram-defs.h> |
22 | #include <folly/stats/MultiLevelTimeSeries-defs.h> |
23 | #include <folly/stats/TimeseriesHistogram.h> |
24 | |
25 | namespace folly { |
26 | |
27 | template <typename T, typename CT, typename C> |
28 | TimeseriesHistogram<T, CT, C>::TimeseriesHistogram( |
29 | ValueType bucketSize, |
30 | ValueType min, |
31 | ValueType max, |
32 | const ContainerType& copyMe) |
33 | : buckets_(bucketSize, min, max, copyMe), |
34 | haveNotSeenValue_(true), |
35 | singleUniqueValue_(false) {} |
36 | |
37 | template <typename T, typename CT, typename C> |
38 | void TimeseriesHistogram<T, CT, C>::addValue( |
39 | TimePoint now, |
40 | const ValueType& value) { |
41 | buckets_.getByValue(value).addValue(now, value); |
42 | maybeHandleSingleUniqueValue(value); |
43 | } |
44 | |
45 | template <typename T, typename CT, typename C> |
46 | void TimeseriesHistogram<T, CT, C>::addValue( |
47 | TimePoint now, |
48 | const ValueType& value, |
49 | uint64_t times) { |
50 | buckets_.getByValue(value).addValue(now, value, times); |
51 | maybeHandleSingleUniqueValue(value); |
52 | } |
53 | |
54 | template <typename T, typename CT, typename C> |
55 | void TimeseriesHistogram<T, CT, C>::addValues( |
56 | TimePoint now, |
57 | const folly::Histogram<ValueType>& hist) { |
58 | CHECK_EQ(hist.getMin(), getMin()); |
59 | CHECK_EQ(hist.getMax(), getMax()); |
60 | CHECK_EQ(hist.getBucketSize(), getBucketSize()); |
61 | CHECK_EQ(hist.getNumBuckets(), getNumBuckets()); |
62 | |
63 | for (size_t n = 0; n < hist.getNumBuckets(); ++n) { |
64 | const typename folly::Histogram<ValueType>::Bucket& histBucket = |
65 | hist.getBucketByIndex(n); |
66 | Bucket& myBucket = buckets_.getByIndex(n); |
67 | myBucket.addValueAggregated(now, histBucket.sum, histBucket.count); |
68 | } |
69 | |
70 | // We don't bother with the singleUniqueValue_ tracking. |
71 | haveNotSeenValue_ = false; |
72 | singleUniqueValue_ = false; |
73 | } |
74 | |
75 | template <typename T, typename CT, typename C> |
76 | void TimeseriesHistogram<T, CT, C>::maybeHandleSingleUniqueValue( |
77 | const ValueType& value) { |
78 | if (haveNotSeenValue_) { |
79 | firstValue_ = value; |
80 | singleUniqueValue_ = true; |
81 | haveNotSeenValue_ = false; |
82 | } else if (singleUniqueValue_) { |
83 | if (value != firstValue_) { |
84 | singleUniqueValue_ = false; |
85 | } |
86 | } |
87 | } |
88 | |
89 | template <typename T, typename CT, typename C> |
90 | T TimeseriesHistogram<T, CT, C>::getPercentileEstimate(double pct, size_t level) |
91 | const { |
92 | if (singleUniqueValue_) { |
93 | return firstValue_; |
94 | } |
95 | |
96 | return buckets_.getPercentileEstimate( |
97 | pct / 100.0, CountFromLevel(level), AvgFromLevel(level)); |
98 | } |
99 | |
100 | template <typename T, typename CT, typename C> |
101 | T TimeseriesHistogram<T, CT, C>::getPercentileEstimate( |
102 | double pct, |
103 | TimePoint start, |
104 | TimePoint end) const { |
105 | if (singleUniqueValue_) { |
106 | return firstValue_; |
107 | } |
108 | |
109 | return buckets_.getPercentileEstimate( |
110 | pct / 100.0, |
111 | CountFromInterval(start, end), |
112 | AvgFromInterval<T>(start, end)); |
113 | } |
114 | |
115 | template <typename T, typename CT, typename C> |
116 | size_t TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx( |
117 | double pct, |
118 | size_t level) const { |
119 | return buckets_.getPercentileBucketIdx(pct / 100.0, CountFromLevel(level)); |
120 | } |
121 | |
122 | template <typename T, typename CT, typename C> |
123 | size_t TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx( |
124 | double pct, |
125 | TimePoint start, |
126 | TimePoint end) const { |
127 | return buckets_.getPercentileBucketIdx( |
128 | pct / 100.0, CountFromInterval(start, end)); |
129 | } |
130 | |
131 | template <typename T, typename CT, typename C> |
132 | void TimeseriesHistogram<T, CT, C>::clear() { |
133 | for (size_t i = 0; i < buckets_.getNumBuckets(); i++) { |
134 | buckets_.getByIndex(i).clear(); |
135 | } |
136 | } |
137 | |
138 | template <typename T, typename CT, typename C> |
139 | void TimeseriesHistogram<T, CT, C>::update(TimePoint now) { |
140 | for (size_t i = 0; i < buckets_.getNumBuckets(); i++) { |
141 | buckets_.getByIndex(i).update(now); |
142 | } |
143 | } |
144 | |
145 | template <typename T, typename CT, typename C> |
146 | std::string TimeseriesHistogram<T, CT, C>::getString(size_t level) const { |
147 | std::string result; |
148 | |
149 | for (size_t i = 0; i < buckets_.getNumBuckets(); i++) { |
150 | if (i > 0) { |
151 | toAppend("," , &result); |
152 | } |
153 | const ContainerType& cont = buckets_.getByIndex(i); |
154 | toAppend( |
155 | buckets_.getBucketMin(i), |
156 | ":" , |
157 | cont.count(level), |
158 | ":" , |
159 | cont.template avg<ValueType>(level), |
160 | &result); |
161 | } |
162 | |
163 | return result; |
164 | } |
165 | |
166 | template <typename T, typename CT, typename C> |
167 | std::string TimeseriesHistogram<T, CT, C>::getString( |
168 | TimePoint start, |
169 | TimePoint end) const { |
170 | std::string result; |
171 | |
172 | for (size_t i = 0; i < buckets_.getNumBuckets(); i++) { |
173 | if (i > 0) { |
174 | toAppend("," , &result); |
175 | } |
176 | const ContainerType& cont = buckets_.getByIndex(i); |
177 | toAppend( |
178 | buckets_.getBucketMin(i), |
179 | ":" , |
180 | cont.count(start, end), |
181 | ":" , |
182 | cont.avg(start, end), |
183 | &result); |
184 | } |
185 | |
186 | return result; |
187 | } |
188 | |
189 | template <class T, class CT, class C> |
190 | void TimeseriesHistogram<T, CT, C>::computeAvgData( |
191 | ValueType* total, |
192 | uint64_t* nsamples, |
193 | size_t level) const { |
194 | for (size_t b = 0; b < buckets_.getNumBuckets(); ++b) { |
195 | const auto& levelObj = buckets_.getByIndex(b).getLevel(level); |
196 | *total += levelObj.sum(); |
197 | *nsamples += levelObj.count(); |
198 | } |
199 | } |
200 | |
201 | template <class T, class CT, class C> |
202 | void TimeseriesHistogram<T, CT, C>::computeAvgData( |
203 | ValueType* total, |
204 | uint64_t* nsamples, |
205 | TimePoint start, |
206 | TimePoint end) const { |
207 | for (size_t b = 0; b < buckets_.getNumBuckets(); ++b) { |
208 | const auto& levelObj = buckets_.getByIndex(b).getLevel(start); |
209 | *total += levelObj.sum(start, end); |
210 | *nsamples += levelObj.count(start, end); |
211 | } |
212 | } |
213 | |
214 | template <typename T, typename CT, typename C> |
215 | void TimeseriesHistogram<T, CT, C>::computeRateData( |
216 | ValueType* total, |
217 | Duration* elapsed, |
218 | size_t level) const { |
219 | for (size_t b = 0; b < buckets_.getNumBuckets(); ++b) { |
220 | const auto& levelObj = buckets_.getByIndex(b).getLevel(level); |
221 | *total += levelObj.sum(); |
222 | *elapsed = std::max(*elapsed, levelObj.elapsed()); |
223 | } |
224 | } |
225 | |
226 | template <class T, class CT, class C> |
227 | void TimeseriesHistogram<T, CT, C>::computeRateData( |
228 | ValueType* total, |
229 | Duration* elapsed, |
230 | TimePoint start, |
231 | TimePoint end) const { |
232 | for (size_t b = 0; b < buckets_.getNumBuckets(); ++b) { |
233 | const auto& level = buckets_.getByIndex(b).getLevel(start); |
234 | *total += level.sum(start, end); |
235 | *elapsed = std::max(*elapsed, level.elapsed(start, end)); |
236 | } |
237 | } |
238 | |
239 | } // namespace folly |
240 | |