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