2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
27 template <typename T, typename CT, typename C>
28 TimeseriesHistogram<T, CT, C>::TimeseriesHistogram(
32 const ContainerType& copyMe)
33 : buckets_(bucketSize, min, max, copyMe),
34 haveNotSeenValue_(true),
35 singleUniqueValue_(false) {}
37 template <typename T, typename CT, typename C>
38 void TimeseriesHistogram<T, CT, C>::addValue(
40 const ValueType& value) {
41 buckets_.getByValue(value).addValue(now, value);
42 maybeHandleSingleUniqueValue(value);
45 template <typename T, typename CT, typename C>
46 void TimeseriesHistogram<T, CT, C>::addValue(
48 const ValueType& value,
50 buckets_.getByValue(value).addValue(now, value, times);
51 maybeHandleSingleUniqueValue(value);
54 template <typename T, typename CT, typename C>
55 void TimeseriesHistogram<T, CT, C>::addValues(
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());
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);
70 // We don't bother with the singleUniqueValue_ tracking.
71 haveNotSeenValue_ = false;
72 singleUniqueValue_ = false;
75 template <typename T, typename CT, typename C>
76 void TimeseriesHistogram<T, CT, C>::maybeHandleSingleUniqueValue(
77 const ValueType& value) {
78 if (haveNotSeenValue_) {
80 singleUniqueValue_ = true;
81 haveNotSeenValue_ = false;
82 } else if (singleUniqueValue_) {
83 if (value != firstValue_) {
84 singleUniqueValue_ = false;
89 template <typename T, typename CT, typename C>
90 T TimeseriesHistogram<T, CT, C>::getPercentileEstimate(double pct, size_t level)
92 if (singleUniqueValue_) {
96 return buckets_.getPercentileEstimate(pct / 100.0, CountFromLevel(level),
100 template <typename T, typename CT, typename C>
101 T TimeseriesHistogram<T, CT, C>::getPercentileEstimate(
104 TimePoint end) const {
105 if (singleUniqueValue_) {
109 return buckets_.getPercentileEstimate(pct / 100.0,
110 CountFromInterval(start, end),
111 AvgFromInterval<T>(start, end));
114 template <typename T, typename CT, typename C>
115 size_t TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx(
117 size_t level) const {
118 return buckets_.getPercentileBucketIdx(pct / 100.0, CountFromLevel(level));
121 template <typename T, typename CT, typename C>
122 size_t TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx(
125 TimePoint end) const {
126 return buckets_.getPercentileBucketIdx(pct / 100.0,
127 CountFromInterval(start, end));
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();
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);
144 template <typename T, typename CT, typename C>
145 std::string TimeseriesHistogram<T, CT, C>::getString(size_t level) const {
148 for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
150 toAppend(",", &result);
152 const ContainerType& cont = buckets_.getByIndex(i);
153 toAppend(buckets_.getBucketMin(i),
154 ":", cont.count(level),
155 ":", cont.template avg<ValueType>(level), &result);
161 template <typename T, typename CT, typename C>
162 std::string TimeseriesHistogram<T, CT, C>::getString(
164 TimePoint end) const {
167 for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
169 toAppend(",", &result);
171 const ContainerType& cont = buckets_.getByIndex(i);
172 toAppend(buckets_.getBucketMin(i),
173 ":", cont.count(start, end),
174 ":", cont.avg(start, end), &result);
180 template <class T, class CT, class C>
181 void TimeseriesHistogram<T, CT, C>::computeAvgData(
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();
192 template <class T, class CT, class C>
193 void TimeseriesHistogram<T, CT, C>::computeAvgData(
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);
205 template <typename T, typename CT, typename C>
206 void TimeseriesHistogram<T, CT, C>::computeRateData(
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());
217 template <class T, class CT, class C>
218 void TimeseriesHistogram<T, CT, C>::computeRateData(
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));