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