2017
[folly.git] / folly / stats / TimeseriesHistogram-defs.h
1 /*
2  * Copyright 2017 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(pct / 100.0, CountFromLevel(level),
97                                         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(pct / 100.0,
110                                         CountFromInterval(start, end),
111                                         AvgFromInterval<T>(start, end));
112 }
113
114 template <typename T, typename CT, typename C>
115 size_t TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx(
116     double pct,
117     size_t level) const {
118   return buckets_.getPercentileBucketIdx(pct / 100.0, CountFromLevel(level));
119 }
120
121 template <typename T, typename CT, typename C>
122 size_t TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx(
123     double pct,
124     TimePoint start,
125     TimePoint end) const {
126   return buckets_.getPercentileBucketIdx(pct / 100.0,
127                                          CountFromInterval(start, end));
128 }
129
130 template <typename T, typename CT, typename C>
131 void TimeseriesHistogram<T, CT, C>::clear() {
132   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
133     buckets_.getByIndex(i).clear();
134   }
135 }
136
137 template <typename T, typename CT, typename C>
138 void TimeseriesHistogram<T, CT, C>::update(TimePoint now) {
139   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
140     buckets_.getByIndex(i).update(now);
141   }
142 }
143
144 template <typename T, typename CT, typename C>
145 std::string TimeseriesHistogram<T, CT, C>::getString(size_t level) const {
146   std::string result;
147
148   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
149     if (i > 0) {
150       toAppend(",", &result);
151     }
152     const ContainerType& cont = buckets_.getByIndex(i);
153     toAppend(buckets_.getBucketMin(i),
154              ":", cont.count(level),
155              ":", cont.template avg<ValueType>(level), &result);
156   }
157
158   return result;
159 }
160
161 template <typename T, typename CT, typename C>
162 std::string TimeseriesHistogram<T, CT, C>::getString(
163     TimePoint start,
164     TimePoint end) const {
165   std::string result;
166
167   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
168     if (i > 0) {
169       toAppend(",", &result);
170     }
171     const ContainerType& cont = buckets_.getByIndex(i);
172     toAppend(buckets_.getBucketMin(i),
173              ":", cont.count(start, end),
174              ":", cont.avg(start, end), &result);
175   }
176
177   return result;
178 }
179
180 template <class T, class CT, class C>
181 void TimeseriesHistogram<T, CT, C>::computeAvgData(
182     ValueType* total,
183     uint64_t* nsamples,
184     size_t level) const {
185   for (size_t b = 0; b < buckets_.getNumBuckets(); ++b) {
186     const auto& levelObj = buckets_.getByIndex(b).getLevel(level);
187     *total += levelObj.sum();
188     *nsamples += levelObj.count();
189   }
190 }
191
192 template <class T, class CT, class C>
193 void TimeseriesHistogram<T, CT, C>::computeAvgData(
194     ValueType* total,
195     uint64_t* nsamples,
196     TimePoint start,
197     TimePoint end) const {
198   for (size_t b = 0; b < buckets_.getNumBuckets(); ++b) {
199     const auto& levelObj = buckets_.getByIndex(b).getLevel(start);
200     *total += levelObj.sum(start, end);
201     *nsamples += levelObj.count(start, end);
202   }
203 }
204
205 template <typename T, typename CT, typename C>
206 void TimeseriesHistogram<T, CT, C>::computeRateData(
207     ValueType* total,
208     Duration* elapsed,
209     size_t level) const {
210   for (size_t b = 0; b < buckets_.getNumBuckets(); ++b) {
211     const auto& levelObj = buckets_.getByIndex(b).getLevel(level);
212     *total += levelObj.sum();
213     *elapsed = std::max(*elapsed, levelObj.elapsed());
214   }
215 }
216
217 template <class T, class CT, class C>
218 void TimeseriesHistogram<T, CT, C>::computeRateData(
219     ValueType* total,
220     Duration* elapsed,
221     TimePoint start,
222     TimePoint end) const {
223   for (size_t b = 0; b < buckets_.getNumBuckets(); ++b) {
224     const auto& level = buckets_.getByIndex(b).getLevel(start);
225     *total += level.sum(start, end);
226     *elapsed = std::max(*elapsed, level.elapsed(start, end));
227   }
228 }
229
230 }  // namespace folly