| /* |
| * Copyright 2015 Facebook, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef FOLLY_TIMESERIES_HISTOGRAM_DEF_H_ |
| #define FOLLY_TIMESERIES_HISTOGRAM_DEF_H_ |
| |
| #include <folly/Conv.h> |
| #include <folly/stats/Histogram-defs.h> |
| #include <folly/stats/MultiLevelTimeSeries-defs.h> |
| #include <folly/stats/BucketedTimeSeries-defs.h> |
| |
| namespace folly { |
| |
| template <class T, class TT, class C> |
| template <typename ReturnType> |
| ReturnType TimeseriesHistogram<T, TT, C>::avg(int level) const { |
| ValueType total = ValueType(); |
| int64_t nsamples = 0; |
| for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) { |
| const auto& levelObj = buckets_.getByIndex(b).getLevel(level); |
| total += levelObj.sum(); |
| nsamples += levelObj.count(); |
| } |
| return folly::detail::avgHelper<ReturnType>(total, nsamples); |
| } |
| |
| template <class T, class TT, class C> |
| template <typename ReturnType> |
| ReturnType TimeseriesHistogram<T, TT, C>::avg(TimeType start, |
| TimeType end) const { |
| ValueType total = ValueType(); |
| int64_t nsamples = 0; |
| for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) { |
| const auto& levelObj = buckets_.getByIndex(b).getLevel(start, end); |
| total += levelObj.sum(start, end); |
| nsamples += levelObj.count(start, end); |
| } |
| return folly::detail::avgHelper<ReturnType>(total, nsamples); |
| } |
| |
| template <class T, class TT, class C> |
| template <typename ReturnType> |
| ReturnType TimeseriesHistogram<T, TT, C>::rate(TimeType start, |
| TimeType end) const { |
| ValueType total = ValueType(); |
| TimeType elapsed(0); |
| for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) { |
| const auto& level = buckets_.getByIndex(b).getLevel(start); |
| total += level.sum(start, end); |
| elapsed = std::max(elapsed, level.elapsed(start, end)); |
| } |
| return folly::detail::rateHelper<ReturnType, TimeType, TimeType>( |
| total, elapsed); |
| } |
| |
| template <typename T, typename TT, typename C> |
| TimeseriesHistogram<T, TT, C>::TimeseriesHistogram(ValueType bucketSize, |
| ValueType min, |
| ValueType max, |
| const ContainerType& copyMe) |
| : buckets_(bucketSize, min, max, copyMe), |
| haveNotSeenValue_(true), |
| singleUniqueValue_(false) { |
| } |
| |
| template <typename T, typename TT, typename C> |
| void TimeseriesHistogram<T, TT, C>::addValue(TimeType now, |
| const ValueType& value) { |
| buckets_.getByValue(value).addValue(now, value); |
| maybeHandleSingleUniqueValue(value); |
| } |
| |
| template <typename T, typename TT, typename C> |
| void TimeseriesHistogram<T, TT, C>::addValue(TimeType now, |
| const ValueType& value, |
| int64_t times) { |
| buckets_.getByValue(value).addValue(now, value, times); |
| maybeHandleSingleUniqueValue(value); |
| } |
| |
| template <typename T, typename TT, typename C> |
| void TimeseriesHistogram<T, TT, C>::addValues( |
| TimeType now, const folly::Histogram<ValueType>& hist) { |
| CHECK_EQ(hist.getMin(), getMin()); |
| CHECK_EQ(hist.getMax(), getMax()); |
| CHECK_EQ(hist.getBucketSize(), getBucketSize()); |
| CHECK_EQ(hist.getNumBuckets(), getNumBuckets()); |
| |
| for (unsigned int n = 0; n < hist.getNumBuckets(); ++n) { |
| const typename folly::Histogram<ValueType>::Bucket& histBucket = |
| hist.getBucketByIndex(n); |
| Bucket& myBucket = buckets_.getByIndex(n); |
| myBucket.addValueAggregated(now, histBucket.sum, histBucket.count); |
| } |
| |
| // We don't bother with the singleUniqueValue_ tracking. |
| haveNotSeenValue_ = false; |
| singleUniqueValue_ = false; |
| } |
| |
| template <typename T, typename TT, typename C> |
| void TimeseriesHistogram<T, TT, C>::maybeHandleSingleUniqueValue( |
| const ValueType& value) { |
| if (haveNotSeenValue_) { |
| firstValue_ = value; |
| singleUniqueValue_ = true; |
| haveNotSeenValue_ = false; |
| } else if (singleUniqueValue_) { |
| if (value != firstValue_) { |
| singleUniqueValue_ = false; |
| } |
| } |
| } |
| |
| template <typename T, typename TT, typename C> |
| T TimeseriesHistogram<T, TT, C>::getPercentileEstimate(double pct, |
| int level) const { |
| if (singleUniqueValue_) { |
| return firstValue_; |
| } |
| |
| return buckets_.getPercentileEstimate(pct / 100.0, CountFromLevel(level), |
| AvgFromLevel(level)); |
| } |
| |
| template <typename T, typename TT, typename C> |
| T TimeseriesHistogram<T, TT, C>::getPercentileEstimate(double pct, |
| TimeType start, |
| TimeType end) const { |
| if (singleUniqueValue_) { |
| return firstValue_; |
| } |
| |
| return buckets_.getPercentileEstimate(pct / 100.0, |
| CountFromInterval(start, end), |
| AvgFromInterval<T>(start, end)); |
| } |
| |
| template <typename T, typename TT, typename C> |
| int TimeseriesHistogram<T, TT, C>::getPercentileBucketIdx( |
| double pct, |
| int level |
| ) const { |
| return buckets_.getPercentileBucketIdx(pct / 100.0, CountFromLevel(level)); |
| } |
| |
| template <typename T, typename TT, typename C> |
| int TimeseriesHistogram<T, TT, C>::getPercentileBucketIdx(double pct, |
| TimeType start, |
| TimeType end) const { |
| return buckets_.getPercentileBucketIdx(pct / 100.0, |
| CountFromInterval(start, end)); |
| } |
| |
| template <typename T, typename TT, typename C> |
| T TimeseriesHistogram<T, TT, C>::rate(int level) const { |
| ValueType total = ValueType(); |
| TimeType elapsed(0); |
| for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) { |
| const auto& levelObj = buckets_.getByIndex(b).getLevel(level); |
| total += levelObj.sum(); |
| elapsed = std::max(elapsed, levelObj.elapsed()); |
| } |
| return elapsed == TimeType(0) ? 0 : (total / elapsed.count()); |
| } |
| |
| template <typename T, typename TT, typename C> |
| void TimeseriesHistogram<T, TT, C>::clear() { |
| for (size_t i = 0; i < buckets_.getNumBuckets(); i++) { |
| buckets_.getByIndex(i).clear(); |
| } |
| } |
| |
| template <typename T, typename TT, typename C> |
| void TimeseriesHistogram<T, TT, C>::update(TimeType now) { |
| for (size_t i = 0; i < buckets_.getNumBuckets(); i++) { |
| buckets_.getByIndex(i).update(now); |
| } |
| } |
| |
| template <typename T, typename TT, typename C> |
| std::string TimeseriesHistogram<T, TT, C>::getString(int level) const { |
| std::string result; |
| |
| for (size_t i = 0; i < buckets_.getNumBuckets(); i++) { |
| if (i > 0) { |
| toAppend(",", &result); |
| } |
| const ContainerType& cont = buckets_.getByIndex(i); |
| toAppend(buckets_.getBucketMin(i), |
| ":", cont.count(level), |
| ":", cont.template avg<ValueType>(level), &result); |
| } |
| |
| return result; |
| } |
| |
| template <typename T, typename TT, typename C> |
| std::string TimeseriesHistogram<T, TT, C>::getString(TimeType start, |
| TimeType end) const { |
| std::string result; |
| |
| for (size_t i = 0; i < buckets_.getNumBuckets(); i++) { |
| if (i > 0) { |
| toAppend(",", &result); |
| } |
| const ContainerType& cont = buckets_.getByIndex(i); |
| toAppend(buckets_.getBucketMin(i), |
| ":", cont.count(start, end), |
| ":", cont.avg(start, end), &result); |
| } |
| |
| return result; |
| } |
| |
| } // namespace folly |
| |
| #endif |