1 | /* |
2 | * Copyright 2013-present 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/stats/MultiLevelTimeSeries.h> |
20 | #include <glog/logging.h> |
21 | |
22 | namespace folly { |
23 | |
24 | template <typename VT, typename CT> |
25 | MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries( |
26 | size_t nBuckets, |
27 | size_t nLevels, |
28 | const Duration levelDurations[]) |
29 | : cachedTime_(), cachedSum_(0), cachedCount_(0) { |
30 | CHECK_GT(nLevels, 0u); |
31 | CHECK(levelDurations); |
32 | |
33 | levels_.reserve(nLevels); |
34 | for (size_t i = 0; i < nLevels; ++i) { |
35 | if (levelDurations[i] == Duration(0)) { |
36 | CHECK_EQ(i, nLevels - 1); |
37 | } else if (i > 0) { |
38 | CHECK(levelDurations[i - 1] < levelDurations[i]); |
39 | } |
40 | levels_.emplace_back(nBuckets, levelDurations[i]); |
41 | } |
42 | } |
43 | |
44 | template <typename VT, typename CT> |
45 | MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries( |
46 | size_t nBuckets, |
47 | std::initializer_list<Duration> durations) |
48 | : cachedTime_(), cachedSum_(0), cachedCount_(0) { |
49 | CHECK_GT(durations.size(), 0u); |
50 | |
51 | levels_.reserve(durations.size()); |
52 | size_t i = 0; |
53 | Duration prev{0}; |
54 | for (auto dur : durations) { |
55 | if (dur == Duration(0)) { |
56 | CHECK_EQ(i, durations.size() - 1); |
57 | } else if (i > 0) { |
58 | CHECK(prev < dur); |
59 | } |
60 | levels_.emplace_back(nBuckets, dur); |
61 | prev = dur; |
62 | i++; |
63 | } |
64 | } |
65 | |
66 | template <typename VT, typename CT> |
67 | void MultiLevelTimeSeries<VT, CT>::addValue( |
68 | TimePoint now, |
69 | const ValueType& val) { |
70 | addValueAggregated(now, val, 1); |
71 | } |
72 | |
73 | template <typename VT, typename CT> |
74 | void MultiLevelTimeSeries<VT, CT>::addValue( |
75 | TimePoint now, |
76 | const ValueType& val, |
77 | uint64_t times) { |
78 | addValueAggregated(now, val * ValueType(times), times); |
79 | } |
80 | |
81 | template <typename VT, typename CT> |
82 | void MultiLevelTimeSeries<VT, CT>::addValueAggregated( |
83 | TimePoint now, |
84 | const ValueType& total, |
85 | uint64_t nsamples) { |
86 | if (cachedTime_ != now) { |
87 | flush(); |
88 | cachedTime_ = now; |
89 | } |
90 | cachedSum_ += total; |
91 | cachedCount_ += nsamples; |
92 | } |
93 | |
94 | template <typename VT, typename CT> |
95 | void MultiLevelTimeSeries<VT, CT>::update(TimePoint now) { |
96 | flush(); |
97 | for (size_t i = 0; i < levels_.size(); ++i) { |
98 | levels_[i].update(now); |
99 | } |
100 | } |
101 | |
102 | template <typename VT, typename CT> |
103 | void MultiLevelTimeSeries<VT, CT>::flush() { |
104 | // update all the underlying levels |
105 | if (cachedCount_ > 0) { |
106 | for (size_t i = 0; i < levels_.size(); ++i) { |
107 | levels_[i].addValueAggregated(cachedTime_, cachedSum_, cachedCount_); |
108 | } |
109 | cachedCount_ = 0; |
110 | cachedSum_ = 0; |
111 | } |
112 | } |
113 | |
114 | template <typename VT, typename CT> |
115 | void MultiLevelTimeSeries<VT, CT>::clear() { |
116 | for (auto& level : levels_) { |
117 | level.clear(); |
118 | } |
119 | |
120 | cachedTime_ = TimePoint(); |
121 | cachedSum_ = 0; |
122 | cachedCount_ = 0; |
123 | } |
124 | |
125 | } // namespace folly |
126 | |