/src/brpc/src/bvar/detail/sampler.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | // Date: Tue Jul 28 18:15:57 CST 2015 |
19 | | |
20 | | #ifndef BVAR_DETAIL_SAMPLER_H |
21 | | #define BVAR_DETAIL_SAMPLER_H |
22 | | |
23 | | #include <vector> |
24 | | #include "butil/containers/linked_list.h"// LinkNode |
25 | | #include "butil/scoped_lock.h" // BAIDU_SCOPED_LOCK |
26 | | #include "butil/logging.h" // LOG() |
27 | | #include "butil/containers/bounded_queue.h"// BoundedQueue |
28 | | #include "butil/type_traits.h" // is_same |
29 | | #include "butil/time.h" // gettimeofday_us |
30 | | #include "butil/class_name.h" |
31 | | |
32 | | namespace bvar { |
33 | | namespace detail { |
34 | | |
35 | | template <typename T> |
36 | | struct Sample { |
37 | | T data; |
38 | | int64_t time_us; |
39 | | |
40 | 0 | Sample() : data(), time_us(0) {} Unexecuted instantiation: bvar::detail::Sample<bvar::detail::PercentileSamples<254ul> >::Sample() Unexecuted instantiation: bvar::detail::Sample<bvar::Stat>::Sample() Unexecuted instantiation: bvar::detail::Sample<double>::Sample() Unexecuted instantiation: bvar::detail::Sample<unsigned long>::Sample() Unexecuted instantiation: bvar::detail::Sample<int>::Sample() Unexecuted instantiation: bvar::detail::Sample<long>::Sample() |
41 | | Sample(const T& data2, int64_t time2) : data(data2), time_us(time2) {} |
42 | | }; |
43 | | |
44 | | // The base class for all samplers whose take_sample() are called periodically. |
45 | | class Sampler : public butil::LinkNode<Sampler> { |
46 | | public: |
47 | | Sampler(); |
48 | | |
49 | | // This function will be called every second(approximately) in a |
50 | | // dedicated thread if schedule() is called. |
51 | | virtual void take_sample() = 0; |
52 | | |
53 | | // Register this sampler globally so that take_sample() will be called |
54 | | // periodically. |
55 | | void schedule(); |
56 | | |
57 | | // Call this function instead of delete to destroy the sampler. Deletion |
58 | | // of the sampler may be delayed for seconds. |
59 | | void destroy(); |
60 | | |
61 | | protected: |
62 | | virtual ~Sampler(); |
63 | | |
64 | | friend class SamplerCollector; |
65 | | bool _used; |
66 | | // Sync destroy() and take_sample(). |
67 | | butil::Mutex _mutex; |
68 | | }; |
69 | | |
70 | | // Representing a non-existing operator so that we can test |
71 | | // is_same<Op, VoidOp>::value to write code for different branches. |
72 | | // The false branch should be removed by compiler at compile-time. |
73 | | struct VoidOp { |
74 | | template <typename T> |
75 | 0 | T operator()(const T&, const T&) const { |
76 | 0 | CHECK(false) << "This function should never be called, abort"; |
77 | 0 | abort(); |
78 | 0 | } Unexecuted instantiation: long bvar::detail::VoidOp::operator()<long>(long const&, long const&) const Unexecuted instantiation: bvar::detail::PercentileSamples<254ul> bvar::detail::VoidOp::operator()<bvar::detail::PercentileSamples<254ul> >(bvar::detail::PercentileSamples<254ul> const&, bvar::detail::PercentileSamples<254ul> const&) const |
79 | | }; |
80 | | |
81 | | // The sampler for reducer-alike variables. |
82 | | // The R should have following methods: |
83 | | // - T reset(); |
84 | | // - T get_value(); |
85 | | // - Op op(); |
86 | | // - InvOp inv_op(); |
87 | | template <typename R, typename T, typename Op, typename InvOp> |
88 | | class ReducerSampler : public Sampler { |
89 | | public: |
90 | | static const time_t MAX_SECONDS_LIMIT = 3600; |
91 | | |
92 | | explicit ReducerSampler(R* reducer) |
93 | 0 | : _reducer(reducer) |
94 | 0 | , _window_size(1) { |
95 | | |
96 | | // Invoked take_sample at begining so the value of the first second |
97 | | // would not be ignored |
98 | 0 | take_sample(); |
99 | 0 | } Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<double>, double, bvar::detail::AddTo<double>, bvar::detail::MinusFrom<double> >::ReducerSampler(bvar::PassiveStatus<double>*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<unsigned long>, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::ReducerSampler(bvar::PassiveStatus<unsigned long>*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >, int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >::ReducerSampler(bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::ReducerSampler(bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<long>, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::ReducerSampler(bvar::PassiveStatus<long>*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::IntRecorder, bvar::Stat, bvar::IntRecorder::AddStat, bvar::IntRecorder::MinusStat>::ReducerSampler(bvar::IntRecorder*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::ReducerSampler(bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::detail::Percentile, bvar::detail::PercentileSamples<254ul>, bvar::detail::Percentile::AddPercentileSamples, bvar::detail::VoidOp>::ReducerSampler(bvar::detail::Percentile*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::ReducerSampler(bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >*) |
100 | 0 | ~ReducerSampler() {} Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<double>, double, bvar::detail::AddTo<double>, bvar::detail::MinusFrom<double> >::~ReducerSampler() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<unsigned long>, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::~ReducerSampler() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >, int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >::~ReducerSampler() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::~ReducerSampler() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<long>, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::~ReducerSampler() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::IntRecorder, bvar::Stat, bvar::IntRecorder::AddStat, bvar::IntRecorder::MinusStat>::~ReducerSampler() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::~ReducerSampler() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::detail::Percentile, bvar::detail::PercentileSamples<254ul>, bvar::detail::Percentile::AddPercentileSamples, bvar::detail::VoidOp>::~ReducerSampler() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::~ReducerSampler() |
101 | | |
102 | 0 | void take_sample() override { |
103 | | // Make _q ready. |
104 | | // If _window_size is larger than what _q can hold, e.g. a larger |
105 | | // Window<> is created after running of sampler, make _q larger. |
106 | 0 | if ((size_t)_window_size + 1 > _q.capacity()) { |
107 | 0 | const size_t new_cap = |
108 | 0 | std::max(_q.capacity() * 2, (size_t)_window_size + 1); |
109 | 0 | const size_t memsize = sizeof(Sample<T>) * new_cap; |
110 | 0 | void* mem = malloc(memsize); |
111 | 0 | if (NULL == mem) { |
112 | 0 | return; |
113 | 0 | } |
114 | 0 | butil::BoundedQueue<Sample<T> > new_q( |
115 | 0 | mem, memsize, butil::OWNS_STORAGE); |
116 | 0 | Sample<T> tmp; |
117 | 0 | while (_q.pop(&tmp)) { |
118 | 0 | new_q.push(tmp); |
119 | 0 | } |
120 | 0 | new_q.swap(_q); |
121 | 0 | } |
122 | | |
123 | 0 | Sample<T> latest; |
124 | 0 | if (butil::is_same<InvOp, VoidOp>::value) { |
125 | | // The operator can't be inversed. |
126 | | // We reset the reducer and save the result as a sample. |
127 | | // Suming up samples gives the result within a window. |
128 | | // In this case, get_value() of _reducer gives wrong answer and |
129 | | // should not be called. |
130 | 0 | latest.data = _reducer->reset(); |
131 | 0 | } else { |
132 | | // The operator can be inversed. |
133 | | // We save the result as a sample. |
134 | | // Inversed operation between latest and oldest sample within a |
135 | | // window gives result. |
136 | | // get_value() of _reducer can still be called. |
137 | 0 | latest.data = _reducer->get_value(); |
138 | 0 | } |
139 | 0 | latest.time_us = butil::gettimeofday_us(); |
140 | 0 | _q.elim_push(latest); |
141 | 0 | } Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::IntRecorder, bvar::Stat, bvar::IntRecorder::AddStat, bvar::IntRecorder::MinusStat>::take_sample() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::detail::Percentile, bvar::detail::PercentileSamples<254ul>, bvar::detail::Percentile::AddPercentileSamples, bvar::detail::VoidOp>::take_sample() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<double>, double, bvar::detail::AddTo<double>, bvar::detail::MinusFrom<double> >::take_sample() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<unsigned long>, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::take_sample() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >, int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >::take_sample() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::take_sample() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<long>, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::take_sample() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::take_sample() Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::take_sample() |
142 | | |
143 | 0 | bool get_value(time_t window_size, Sample<T>* result) { |
144 | 0 | if (window_size <= 0) { |
145 | 0 | LOG(FATAL) << "Invalid window_size=" << window_size; |
146 | 0 | return false; |
147 | 0 | } |
148 | 0 | BAIDU_SCOPED_LOCK(_mutex); |
149 | 0 | if (_q.size() <= 1UL) { |
150 | | // We need more samples to get reasonable result. |
151 | 0 | return false; |
152 | 0 | } |
153 | 0 | Sample<T>* oldest = _q.bottom(window_size); |
154 | 0 | if (NULL == oldest) { |
155 | 0 | oldest = _q.top(); |
156 | 0 | } |
157 | 0 | Sample<T>* latest = _q.bottom(); |
158 | 0 | DCHECK(latest != oldest); |
159 | 0 | if (butil::is_same<InvOp, VoidOp>::value) { |
160 | | // No inverse op. Sum up all samples within the window. |
161 | 0 | result->data = latest->data; |
162 | 0 | for (int i = 1; true; ++i) { |
163 | 0 | Sample<T>* e = _q.bottom(i); |
164 | 0 | if (e == oldest) { |
165 | 0 | break; |
166 | 0 | } |
167 | 0 | _reducer->op()(result->data, e->data); |
168 | 0 | } |
169 | 0 | } else { |
170 | | // Diff the latest and oldest sample within the window. |
171 | 0 | result->data = latest->data; |
172 | 0 | _reducer->inv_op()(result->data, oldest->data); |
173 | 0 | } |
174 | 0 | result->time_us = latest->time_us - oldest->time_us; |
175 | 0 | return true; |
176 | 0 | } Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::IntRecorder, bvar::Stat, bvar::IntRecorder::AddStat, bvar::IntRecorder::MinusStat>::get_value(long, bvar::detail::Sample<bvar::Stat>*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::get_value(long, bvar::detail::Sample<long>*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::detail::Percentile, bvar::detail::PercentileSamples<254ul>, bvar::detail::Percentile::AddPercentileSamples, bvar::detail::VoidOp>::get_value(long, bvar::detail::Sample<bvar::detail::PercentileSamples<254ul> >*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<double>, double, bvar::detail::AddTo<double>, bvar::detail::MinusFrom<double> >::get_value(long, bvar::detail::Sample<double>*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<unsigned long>, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::get_value(long, bvar::detail::Sample<unsigned long>*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >, int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >::get_value(long, bvar::detail::Sample<int>*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::get_value(long, bvar::detail::Sample<long>*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<long>, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::get_value(long, bvar::detail::Sample<long>*) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::get_value(long, bvar::detail::Sample<unsigned long>*) |
177 | | |
178 | | // Change the time window which can only go larger. |
179 | 0 | int set_window_size(time_t window_size) { |
180 | 0 | if (window_size <= 0 || window_size > MAX_SECONDS_LIMIT) { |
181 | 0 | LOG(ERROR) << "Invalid window_size=" << window_size; |
182 | 0 | return -1; |
183 | 0 | } |
184 | 0 | BAIDU_SCOPED_LOCK(_mutex); |
185 | 0 | if (window_size > _window_size) { |
186 | 0 | _window_size = window_size; |
187 | 0 | } |
188 | 0 | return 0; |
189 | 0 | } Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<double>, double, bvar::detail::AddTo<double>, bvar::detail::MinusFrom<double> >::set_window_size(long) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<unsigned long>, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::set_window_size(long) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >, int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >::set_window_size(long) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::set_window_size(long) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<long>, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::set_window_size(long) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::IntRecorder, bvar::Stat, bvar::IntRecorder::AddStat, bvar::IntRecorder::MinusStat>::set_window_size(long) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::set_window_size(long) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::detail::Percentile, bvar::detail::PercentileSamples<254ul>, bvar::detail::Percentile::AddPercentileSamples, bvar::detail::VoidOp>::set_window_size(long) Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::set_window_size(long) |
190 | | |
191 | 0 | void get_samples(std::vector<T> *samples, time_t window_size) { |
192 | 0 | if (window_size <= 0) { |
193 | 0 | LOG(FATAL) << "Invalid window_size=" << window_size; |
194 | 0 | return; |
195 | 0 | } |
196 | 0 | BAIDU_SCOPED_LOCK(_mutex); |
197 | 0 | if (_q.size() <= 1) { |
198 | | // We need more samples to get reasonable result. |
199 | 0 | return; |
200 | 0 | } |
201 | 0 | Sample<T>* oldest = _q.bottom(window_size); |
202 | 0 | if (NULL == oldest) { |
203 | 0 | oldest = _q.top(); |
204 | 0 | } |
205 | 0 | for (int i = 1; true; ++i) { |
206 | 0 | Sample<T>* e = _q.bottom(i); |
207 | 0 | if (e == oldest) { |
208 | 0 | break; |
209 | 0 | } |
210 | 0 | samples->push_back(e->data); |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | | private: |
215 | | R* _reducer; |
216 | | time_t _window_size; |
217 | | butil::BoundedQueue<Sample<T> > _q; |
218 | | }; |
219 | | |
220 | | } // namespace detail |
221 | | } // namespace bvar |
222 | | |
223 | | #endif // BVAR_DETAIL_SAMPLER_H |