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