abc7dee1d7ffdb659d80073f126f346d6fd09344
[folly.git] / folly / stats / TimeseriesHistogram-defs.h
1 /*
2  * Copyright 2013 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 #ifndef FOLLY_TIMESERIES_HISTOGRAM_DEF_H_
18 #define FOLLY_TIMESERIES_HISTOGRAM_DEF_H_
19
20 #include "folly/Conv.h"
21 #include "folly/stats/Histogram-defs.h"
22 #include "folly/stats/MultiLevelTimeSeries-defs.h"
23 #include "folly/stats/BucketedTimeSeries-defs.h"
24
25 namespace folly {
26
27 template <class T, class TT, class C>
28 template <typename ReturnType>
29 ReturnType TimeseriesHistogram<T, TT, C>::avg(int level) const {
30   ValueType total = ValueType();
31   int64_t count = 0;
32   for (int b = 0; b < buckets_.getNumBuckets(); ++b) {
33     const auto& levelObj = buckets_.getByIndex(b).getLevel(level);
34     total += levelObj.sum();
35     count += levelObj.count();
36   }
37   return folly::detail::avgHelper<ReturnType>(total, count);
38 }
39
40 template <class T, class TT, class C>
41 template <typename ReturnType>
42 ReturnType TimeseriesHistogram<T, TT, C>::avg(TimeType start,
43                                               TimeType end) const {
44   ValueType total = ValueType();
45   int64_t count = 0;
46   for (int b = 0; b < buckets_.getNumBuckets(); ++b) {
47     const auto& levelObj = buckets_.getByIndex(b).getLevel(start, end);
48     total += levelObj.sum(start, end);
49     count += levelObj.count(start, end);
50   }
51   return folly::detail::avgHelper<ReturnType>(total, count);
52 }
53
54 template <class T, class TT, class C>
55 template <typename ReturnType>
56 ReturnType TimeseriesHistogram<T, TT, C>::rate(TimeType start,
57                                                TimeType end) const {
58   ValueType total = ValueType();
59   TimeType elapsed(0);
60   for (int b = 0; b < buckets_.getNumBuckets(); ++b) {
61     const auto& level = buckets_.getByIndex(b).getLevel(start);
62     total += level.sum(start, end);
63     elapsed = std::max(elapsed, level.elapsed(start, end));
64   }
65   return folly::detail::rateHelper<ReturnType, TimeType, TimeType>(
66       total, elapsed);
67 }
68
69 template <typename T, typename TT, typename C>
70 TimeseriesHistogram<T, TT, C>::TimeseriesHistogram(ValueType bucketSize,
71                                             ValueType min,
72                                             ValueType max,
73                                             const ContainerType& copyMe)
74   : buckets_(bucketSize, min, max, copyMe),
75     haveNotSeenValue_(true),
76     singleUniqueValue_(false) {
77 }
78
79 template <typename T, typename TT, typename C>
80 void TimeseriesHistogram<T, TT, C>::addValue(TimeType now,
81                                              const ValueType& value) {
82   buckets_.getByValue(value).addValue(now, value);
83   maybeHandleSingleUniqueValue(value);
84 }
85
86 template <typename T, typename TT, typename C>
87 void TimeseriesHistogram<T, TT, C>::addValue(TimeType now,
88                                       const ValueType& value,
89                                       int64_t times) {
90   buckets_.getByValue(value).addValue(now, value, times);
91   maybeHandleSingleUniqueValue(value);
92 }
93
94 template <typename T, typename TT, typename C>
95 void TimeseriesHistogram<T, TT, C>::addValues(
96     TimeType now, const folly::Histogram<ValueType>& hist) {
97   CHECK_EQ(hist.getMin(), getMin());
98   CHECK_EQ(hist.getMax(), getMax());
99   CHECK_EQ(hist.getBucketSize(), getBucketSize());
100   CHECK_EQ(hist.getNumBuckets(), getNumBuckets());
101
102   for (unsigned int n = 0; n < hist.getNumBuckets(); ++n) {
103     const typename folly::Histogram<ValueType>::Bucket& histBucket =
104       hist.getBucketByIndex(n);
105     Bucket& myBucket = buckets_.getByIndex(n);
106     myBucket.addValueAggregated(now, histBucket.sum, histBucket.count);
107   }
108
109   // We don't bother with the singleUniqueValue_ tracking.
110   haveNotSeenValue_ = false;
111   singleUniqueValue_ = false;
112 }
113
114 template <typename T, typename TT, typename C>
115 void TimeseriesHistogram<T, TT, C>::maybeHandleSingleUniqueValue(
116   const ValueType& value) {
117   if (haveNotSeenValue_) {
118     firstValue_ = value;
119     singleUniqueValue_ = true;
120     haveNotSeenValue_ = false;
121   } else if (singleUniqueValue_) {
122     if (value != firstValue_) {
123       singleUniqueValue_ = false;
124     }
125   }
126 }
127
128 template <typename T, typename TT, typename C>
129 T TimeseriesHistogram<T, TT, C>::getPercentileEstimate(double pct,
130                                                        int level) const {
131   if (singleUniqueValue_) {
132     return firstValue_;
133   }
134
135   return buckets_.getPercentileEstimate(pct / 100.0, CountFromLevel(level),
136                                         AvgFromLevel(level));
137 }
138
139 template <typename T, typename TT, typename C>
140 T TimeseriesHistogram<T, TT, C>::getPercentileEstimate(double pct,
141                                                 TimeType start,
142                                                 TimeType end) const {
143   if (singleUniqueValue_) {
144     return firstValue_;
145   }
146
147   return buckets_.getPercentileEstimate(pct / 100.0,
148                                         CountFromInterval(start, end),
149                                         AvgFromInterval<T>(start, end));
150 }
151
152 template <typename T, typename TT, typename C>
153 int TimeseriesHistogram<T, TT, C>::getPercentileBucketIdx(
154   double pct,
155   int level
156 ) const {
157   return buckets_.getPercentileBucketIdx(pct / 100.0, CountFromLevel(level));
158 }
159
160 template <typename T, typename TT, typename C>
161 int TimeseriesHistogram<T, TT, C>::getPercentileBucketIdx(double pct,
162                                                    TimeType start,
163                                                    TimeType end) const {
164   return buckets_.getPercentileBucketIdx(pct / 100.0,
165                                          CountFromInterval(start, end));
166 }
167
168 template <typename T, typename TT, typename C>
169 T TimeseriesHistogram<T, TT, C>::rate(int level) const {
170   ValueType total = ValueType();
171   TimeType elapsed(0);
172   for (int b = 0; b < buckets_.getNumBuckets(); ++b) {
173     const auto& levelObj = buckets_.getByIndex(b).getLevel(level);
174     total += levelObj.sum();
175     elapsed = std::max(elapsed, levelObj.elapsed());
176   }
177   return elapsed == TimeType(0) ? 0 : (total / elapsed.count());
178 }
179
180 template <typename T, typename TT, typename C>
181 void TimeseriesHistogram<T, TT, C>::clear() {
182   for (int i = 0; i < buckets_.getNumBuckets(); i++) {
183     buckets_.getByIndex(i).clear();
184   }
185 }
186
187 template <typename T, typename TT, typename C>
188 void TimeseriesHistogram<T, TT, C>::update(TimeType now) {
189   for (int i = 0; i < buckets_.getNumBuckets(); i++) {
190     buckets_.getByIndex(i).update(now);
191   }
192 }
193
194 template <typename T, typename TT, typename C>
195 std::string TimeseriesHistogram<T, TT, C>::getString(int level) const {
196   std::string result;
197
198   for (int i = 0; i < buckets_.getNumBuckets(); i++) {
199     if (i > 0) {
200       toAppend(",", &result);
201     }
202     const ContainerType& cont = buckets_.getByIndex(i);
203     toAppend(buckets_.getBucketMin(i),
204              ":", cont.count(level),
205              ":", cont.template avg<ValueType>(level), &result);
206   }
207
208   return result;
209 }
210
211 template <typename T, typename TT, typename C>
212 std::string TimeseriesHistogram<T, TT, C>::getString(TimeType start,
213                                                      TimeType end) const {
214   std::string result;
215
216   for (int i = 0; i < buckets_.getNumBuckets(); i++) {
217     if (i > 0) {
218       toAppend(",", &result);
219     }
220     const ContainerType& cont = buckets_.getByIndex(i);
221     toAppend(buckets_.getBucketMin(i),
222              ":", cont.count(start, end),
223              ":", cont.avg(start, end), &result);
224   }
225
226   return result;
227 }
228
229 }  // namespace folly
230
231 #endif