/src/brpc/src/bvar/reducer.h
Line | Count | Source |
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 2014/09/24 16:01:08 |
19 | | |
20 | | #ifndef BVAR_REDUCER_H |
21 | | #define BVAR_REDUCER_H |
22 | | |
23 | | #include <limits> // std::numeric_limits |
24 | | #include "butil/logging.h" // LOG() |
25 | | #include "butil/type_traits.h" // butil::add_cr_non_integral |
26 | | #include "butil/class_name.h" // class_name_str |
27 | | #include "bvar/variable.h" // Variable |
28 | | #include "bvar/detail/combiner.h" // detail::AgentCombiner |
29 | | #include "bvar/detail/sampler.h" // ReducerSampler |
30 | | #include "bvar/detail/series.h" |
31 | | #include "bvar/window.h" |
32 | | #if WITH_BABYLON_COUNTER |
33 | | #include "babylon/concurrent/counter.h" |
34 | | #endif // WITH_BABYLON_COUNTER |
35 | | |
36 | | namespace bvar { |
37 | | |
38 | | namespace detail { |
39 | | template<typename O, typename T, typename Op> |
40 | | class SeriesSamplerImpl : public Sampler { |
41 | | public: |
42 | | SeriesSamplerImpl(O* owner, const Op& op) |
43 | 0 | : _owner(owner), _series(op) {}Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>, bvar::Collected*, bvar::CombineCollected>::SeriesSamplerImpl(bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>*, bvar::CombineCollected const&) Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>, bvar::detail::Sampler*, bvar::detail::CombineSampler>::SeriesSamplerImpl(bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>*, bvar::detail::CombineSampler const&) Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long> >::SeriesSamplerImpl(bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>*, bvar::detail::MaxTo<long> const&) Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long> >::SeriesSamplerImpl(bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >*, bvar::detail::AddTo<long> const&) |
44 | 0 | void take_sample() override { _series.append(_owner->get_value()); }Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long> >::take_sample() Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>, bvar::Collected*, bvar::CombineCollected>::take_sample() Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>, bvar::detail::Sampler*, bvar::detail::CombineSampler>::take_sample() Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long> >::take_sample() |
45 | 0 | void describe(std::ostream& os) { _series.describe(os, NULL); }Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long> >::describe(std::basic_ostream<char, std::char_traits<char> >&) Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>, bvar::Collected*, bvar::CombineCollected>::describe(std::basic_ostream<char, std::char_traits<char> >&) Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>, bvar::detail::Sampler*, bvar::detail::CombineSampler>::describe(std::basic_ostream<char, std::char_traits<char> >&) Unexecuted instantiation: bvar::detail::SeriesSamplerImpl<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long> >::describe(std::basic_ostream<char, std::char_traits<char> >&) |
46 | | |
47 | | private: |
48 | | O* _owner; |
49 | | Series<T, Op> _series; |
50 | | }; |
51 | | |
52 | | #if WITH_BABYLON_COUNTER |
53 | | template<typename T, typename Counter, typename Op, typename InvOp> |
54 | | class BabylonVariable: public Variable { |
55 | | public: |
56 | | typedef ReducerSampler<BabylonVariable, T, Op, InvOp> sampler_type; |
57 | | typedef SeriesSamplerImpl<BabylonVariable, T, Op> series_sampler_type; |
58 | | |
59 | | BabylonVariable() = default; |
60 | | |
61 | | template<typename U = T, typename std::enable_if< |
62 | | !std::is_constructible<Counter, U>::value, bool>::type = false> |
63 | | BabylonVariable(U) {} |
64 | | // For Maxer. |
65 | | template<typename U = T, typename std::enable_if< |
66 | | std::is_constructible<Counter, U>::value, bool>::type = false> |
67 | | BabylonVariable(U default_value) : _counter(default_value) {} |
68 | | |
69 | | DISALLOW_COPY_AND_MOVE(BabylonVariable); |
70 | | |
71 | | ~BabylonVariable() override { |
72 | | hide(); |
73 | | if (NULL != _sampler) { |
74 | | _sampler->destroy(); |
75 | | } |
76 | | if (NULL != _series_sampler) { |
77 | | _series_sampler->destroy(); |
78 | | } |
79 | | } |
80 | | |
81 | | BabylonVariable& operator<<(T value) { |
82 | | _counter << value; |
83 | | return *this; |
84 | | } |
85 | | |
86 | | sampler_type* get_sampler() { |
87 | | if (NULL == _sampler) { |
88 | | _sampler = new sampler_type(this); |
89 | | _sampler->schedule(); |
90 | | } |
91 | | return _sampler; |
92 | | } |
93 | | |
94 | | T get_value() const { |
95 | | return _counter.value(); |
96 | | } |
97 | | |
98 | | T reset() { |
99 | | if (BAIDU_UNLIKELY((!butil::is_same<VoidOp, InvOp>::value))) { |
100 | | CHECK(false) << "You should not call Reducer<" << butil::class_name_str<T>() |
101 | | << ", " << butil::class_name_str<Op>() << ">::get_value() when a" |
102 | | << " Window<> is used because the operator does not have inverse."; |
103 | | return get_value(); |
104 | | } |
105 | | |
106 | | T result = _counter.value(); |
107 | | _counter.reset(); |
108 | | return result; |
109 | | } |
110 | | |
111 | | bool valid() const { return true; } |
112 | | |
113 | | const Op& op() const { return _op; } |
114 | | const InvOp& inv_op() const { return _inv_op;} |
115 | | |
116 | | void describe(std::ostream& os, bool quote_string) const override { |
117 | | if (butil::is_same<T, std::string>::value && quote_string) { |
118 | | os << '"' << get_value() << '"'; |
119 | | } else { |
120 | | os << get_value(); |
121 | | } |
122 | | } |
123 | | |
124 | | int describe_series(std::ostream& os, const SeriesOptions& options) const override { |
125 | | if (NULL == _series_sampler) { |
126 | | return 1; |
127 | | } |
128 | | if (!options.test_only) { |
129 | | _series_sampler->describe(os); |
130 | | } |
131 | | return 0; |
132 | | } |
133 | | |
134 | | protected: |
135 | | int expose_impl(const butil::StringPiece& prefix, |
136 | | const butil::StringPiece& name, |
137 | | DisplayFilter display_filter) override { |
138 | | const int rc = Variable::expose_impl(prefix, name, display_filter); |
139 | | if (rc == 0 && NULL == _series_sampler && |
140 | | !butil::is_same<InvOp, VoidOp>::value && |
141 | | !butil::is_same<T, std::string>::value && |
142 | | FLAGS_save_series) { |
143 | | _series_sampler = new series_sampler_type(this, _op); |
144 | | _series_sampler->schedule(); |
145 | | } |
146 | | return rc; |
147 | | } |
148 | | |
149 | | private: |
150 | | Counter _counter; |
151 | | sampler_type* _sampler{NULL}; |
152 | | series_sampler_type* _series_sampler{NULL}; |
153 | | Op _op; |
154 | | InvOp _inv_op; |
155 | | }; |
156 | | #endif // WITH_BABYLON_COUNTER |
157 | | } // namespace detail |
158 | | |
159 | | // Reduce multiple values into one with `Op': e1 Op e2 Op e3 ... |
160 | | // `Op' shall satisfy: |
161 | | // - associative: a Op (b Op c) == (a Op b) Op c |
162 | | // - commutative: a Op b == b Op a; |
163 | | // - no side effects: a Op b never changes if a and b are fixed. |
164 | | // otherwise the result is undefined. |
165 | | // |
166 | | // For performance issues, we don't let Op return value, instead it shall |
167 | | // set the result to the first parameter in-place. Namely to add two values, |
168 | | // "+=" should be implemented rather than "+". |
169 | | // |
170 | | // Reducer works for non-primitive T which satisfies: |
171 | | // - T() should be the identity of Op. |
172 | | // - stream << v should compile and put description of v into the stream |
173 | | // Example: |
174 | | // class MyType { |
175 | | // friend std::ostream& operator<<(std::ostream& os, const MyType&); |
176 | | // public: |
177 | | // MyType() : _x(0) {} |
178 | | // explicit MyType(int x) : _x(x) {} |
179 | | // void operator+=(const MyType& rhs) const { |
180 | | // _x += rhs._x; |
181 | | // } |
182 | | // private: |
183 | | // int _x; |
184 | | // }; |
185 | | // std::ostream& operator<<(std::ostream& os, const MyType& value) { |
186 | | // return os << "MyType{" << value._x << "}"; |
187 | | // } |
188 | | // bvar::Adder<MyType> my_type_sum; |
189 | | // my_type_sum << MyType(1) << MyType(2) << MyType(3); |
190 | | // LOG(INFO) << my_type_sum; // "MyType{6}" |
191 | | |
192 | | template <typename T, typename Op, typename InvOp = detail::VoidOp> |
193 | | class Reducer : public Variable { |
194 | | public: |
195 | | typedef detail::AgentCombiner<T, T, Op> combiner_type; |
196 | | typedef typename combiner_type::self_shared_type shared_combiner_type; |
197 | | typedef typename combiner_type::Agent agent_type; |
198 | | typedef detail::ReducerSampler<Reducer, T, Op, InvOp> sampler_type; |
199 | | typedef detail::SeriesSamplerImpl<Reducer, T, Op> SeriesSampler; |
200 | | |
201 | | // The `identify' must satisfy: identity Op a == a |
202 | | explicit Reducer(typename butil::add_cr_non_integral<T>::type identity = T(), |
203 | | const Op& op = Op(), const InvOp& inv_op = InvOp()) |
204 | 2 | : _combiner(std::make_shared<combiner_type>(identity, identity, op)) |
205 | 2 | , _sampler(NULL) , _series_sampler(NULL) , _inv_op(inv_op) {}Unexecuted instantiation: bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>::Reducer(bvar::Collected* const&, bvar::CombineCollected const&, bvar::detail::VoidOp const&) bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>::Reducer(bvar::detail::Sampler* const&, bvar::detail::CombineSampler const&, bvar::detail::VoidOp const&) Line | Count | Source | 204 | 2 | : _combiner(std::make_shared<combiner_type>(identity, identity, op)) | 205 | 2 | , _sampler(NULL) , _series_sampler(NULL) , _inv_op(inv_op) {} |
Unexecuted instantiation: bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::Reducer(long, bvar::detail::MaxTo<long> const&, bvar::detail::VoidOp const&) Unexecuted instantiation: bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::Reducer(long, bvar::detail::AddTo<long> const&, bvar::detail::MinusFrom<long> const&) |
206 | | |
207 | 0 | ~Reducer() override { |
208 | | // Calling hide() manually is a MUST required by Variable. |
209 | 0 | hide(); |
210 | 0 | if (_sampler) { |
211 | 0 | _sampler->destroy(); |
212 | 0 | _sampler = NULL; |
213 | 0 | } |
214 | 0 | if (_series_sampler) { |
215 | 0 | _series_sampler->destroy(); |
216 | 0 | _series_sampler = NULL; |
217 | 0 | } |
218 | 0 | } Unexecuted instantiation: bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>::~Reducer() Unexecuted instantiation: bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>::~Reducer() Unexecuted instantiation: bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::~Reducer() Unexecuted instantiation: bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::~Reducer() |
219 | | |
220 | | // Add a value. |
221 | | // Returns self reference for chaining. |
222 | | Reducer& operator<<(typename butil::add_cr_non_integral<T>::type value); |
223 | | |
224 | | // Get reduced value. |
225 | | // Notice that this function walks through threads that ever add values |
226 | | // into this reducer. You should avoid calling it frequently. |
227 | 0 | T get_value() const { |
228 | 0 | CHECK(!(butil::is_same<InvOp, detail::VoidOp>::value) || _sampler == NULL) |
229 | 0 | << "You should not call Reducer<" << butil::class_name_str<T>() |
230 | 0 | << ", " << butil::class_name_str<Op>() << ">::get_value() when a" |
231 | 0 | << " Window<> is used because the operator does not have inverse."; |
232 | 0 | return _combiner->combine_agents(); |
233 | 0 | } Unexecuted instantiation: bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::get_value() const Unexecuted instantiation: bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>::get_value() const Unexecuted instantiation: bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>::get_value() const Unexecuted instantiation: bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::get_value() const |
234 | | |
235 | | |
236 | | // Reset the reduced value to T(). |
237 | | // Returns the reduced value before reset. |
238 | 6 | T reset() { return _combiner->reset_all_agents(); }Unexecuted instantiation: bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>::reset() bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>::reset() Line | Count | Source | 238 | 6 | T reset() { return _combiner->reset_all_agents(); } |
Unexecuted instantiation: bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::reset() |
239 | | |
240 | 0 | void describe(std::ostream& os, bool quote_string) const override { |
241 | 0 | if (butil::is_same<T, std::string>::value && quote_string) { |
242 | 0 | os << '"' << get_value() << '"'; |
243 | 0 | } else { |
244 | 0 | os << get_value(); |
245 | 0 | } |
246 | 0 | } Unexecuted instantiation: bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::describe(std::basic_ostream<char, std::char_traits<char> >&, bool) const Unexecuted instantiation: bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>::describe(std::basic_ostream<char, std::char_traits<char> >&, bool) const Unexecuted instantiation: bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>::describe(std::basic_ostream<char, std::char_traits<char> >&, bool) const Unexecuted instantiation: bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::describe(std::basic_ostream<char, std::char_traits<char> >&, bool) const |
247 | | |
248 | | #ifdef BAIDU_INTERNAL |
249 | | void get_value(boost::any* value) const override { *value = get_value(); } |
250 | | #endif |
251 | | |
252 | | // True if this reducer is constructed successfully. |
253 | | bool valid() const { return _combiner->valid(); } |
254 | | |
255 | | // Get instance of Op. |
256 | 0 | const Op& op() const { return _combiner->op(); } |
257 | 0 | const InvOp& inv_op() const { return _inv_op; } |
258 | | |
259 | 0 | sampler_type* get_sampler() { |
260 | 0 | if (NULL == _sampler) { |
261 | 0 | _sampler = new sampler_type(this); |
262 | 0 | _sampler->schedule(); |
263 | 0 | } |
264 | 0 | return _sampler; |
265 | 0 | } |
266 | | |
267 | 0 | int describe_series(std::ostream& os, const SeriesOptions& options) const override { |
268 | 0 | if (_series_sampler == NULL) { |
269 | 0 | return 1; |
270 | 0 | } |
271 | 0 | if (!options.test_only) { |
272 | 0 | _series_sampler->describe(os); |
273 | 0 | } |
274 | 0 | return 0; |
275 | 0 | } Unexecuted instantiation: bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::describe_series(std::basic_ostream<char, std::char_traits<char> >&, bvar::SeriesOptions const&) const Unexecuted instantiation: bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>::describe_series(std::basic_ostream<char, std::char_traits<char> >&, bvar::SeriesOptions const&) const Unexecuted instantiation: bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>::describe_series(std::basic_ostream<char, std::char_traits<char> >&, bvar::SeriesOptions const&) const Unexecuted instantiation: bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::describe_series(std::basic_ostream<char, std::char_traits<char> >&, bvar::SeriesOptions const&) const |
276 | | |
277 | | protected: |
278 | | int expose_impl(const butil::StringPiece& prefix, |
279 | | const butil::StringPiece& name, |
280 | 0 | DisplayFilter display_filter) override { |
281 | 0 | const int rc = Variable::expose_impl(prefix, name, display_filter); |
282 | 0 | if (rc == 0 && |
283 | 0 | _series_sampler == NULL && |
284 | 0 | !butil::is_same<InvOp, detail::VoidOp>::value && |
285 | 0 | !butil::is_same<T, std::string>::value && |
286 | 0 | FLAGS_save_series) { |
287 | 0 | _series_sampler = new SeriesSampler(this, _combiner->op()); |
288 | 0 | _series_sampler->schedule(); |
289 | 0 | } |
290 | 0 | return rc; |
291 | 0 | } Unexecuted instantiation: bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::expose_impl(butil::BasicStringPiece<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, butil::BasicStringPiece<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, bvar::DisplayFilter) Unexecuted instantiation: bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>::expose_impl(butil::BasicStringPiece<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, butil::BasicStringPiece<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, bvar::DisplayFilter) Unexecuted instantiation: bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>::expose_impl(butil::BasicStringPiece<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, butil::BasicStringPiece<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, bvar::DisplayFilter) Unexecuted instantiation: bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::expose_impl(butil::BasicStringPiece<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, butil::BasicStringPiece<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, bvar::DisplayFilter) |
292 | | |
293 | | private: |
294 | | shared_combiner_type _combiner; |
295 | | sampler_type* _sampler; |
296 | | SeriesSampler* _series_sampler; |
297 | | InvOp _inv_op; |
298 | | }; |
299 | | |
300 | | template <typename T, typename Op, typename InvOp> |
301 | | inline Reducer<T, Op, InvOp>& Reducer<T, Op, InvOp>::operator<<( |
302 | 8 | typename butil::add_cr_non_integral<T>::type value) { |
303 | | // It's wait-free for most time |
304 | 8 | agent_type* agent = _combiner->get_or_create_tls_agent(); |
305 | 8 | if (__builtin_expect(!agent, 0)) { |
306 | 0 | LOG(FATAL) << "Fail to create agent"; |
307 | 0 | return *this; |
308 | 0 | } |
309 | 8 | agent->element.modify(_combiner->op(), value); |
310 | 8 | return *this; |
311 | 8 | } Unexecuted instantiation: bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::operator<<(long) Unexecuted instantiation: bvar::Reducer<bvar::Collected*, bvar::CombineCollected, bvar::detail::VoidOp>::operator<<(bvar::Collected* const&) bvar::Reducer<bvar::detail::Sampler*, bvar::detail::CombineSampler, bvar::detail::VoidOp>::operator<<(bvar::detail::Sampler* const&) Line | Count | Source | 302 | 8 | typename butil::add_cr_non_integral<T>::type value) { | 303 | | // It's wait-free for most time | 304 | 8 | agent_type* agent = _combiner->get_or_create_tls_agent(); | 305 | 8 | if (__builtin_expect(!agent, 0)) { | 306 | 0 | LOG(FATAL) << "Fail to create agent"; | 307 | 0 | return *this; | 308 | 0 | } | 309 | 8 | agent->element.modify(_combiner->op(), value); | 310 | 8 | return *this; | 311 | 8 | } |
Unexecuted instantiation: bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::operator<<(long) |
312 | | |
313 | | // =================== Common reducers =================== |
314 | | |
315 | | // bvar::Adder<int> sum; |
316 | | // sum << 1 << 2 << 3 << 4; |
317 | | // LOG(INFO) << sum.get_value(); // 10 |
318 | | // Commonly used functors |
319 | | namespace detail { |
320 | | template <typename Tp> |
321 | | struct AddTo { |
322 | | void operator()(Tp & lhs, |
323 | | typename butil::add_cr_non_integral<Tp>::type rhs) const |
324 | 0 | { lhs += rhs; }Unexecuted instantiation: bvar::detail::AddTo<double>::operator()(double&, double const&) const Unexecuted instantiation: bvar::detail::AddTo<long>::operator()(long&, long) const Unexecuted instantiation: bvar::detail::AddTo<bvar::Vector<long, 4ul> >::operator()(bvar::Vector<long, 4ul>&, bvar::Vector<long, 4ul> const&) const Unexecuted instantiation: bvar::detail::AddTo<unsigned long>::operator()(unsigned long&, unsigned long) const Unexecuted instantiation: bvar::detail::AddTo<int>::operator()(int&, int) const |
325 | | }; |
326 | | template <typename Tp> |
327 | | struct MinusFrom { |
328 | | void operator()(Tp & lhs, |
329 | | typename butil::add_cr_non_integral<Tp>::type rhs) const |
330 | 0 | { lhs -= rhs; }Unexecuted instantiation: bvar::detail::MinusFrom<double>::operator()(double&, double const&) const Unexecuted instantiation: bvar::detail::MinusFrom<unsigned long>::operator()(unsigned long&, unsigned long) const Unexecuted instantiation: bvar::detail::MinusFrom<long>::operator()(long&, long) const |
331 | | }; |
332 | | } // namespace detail |
333 | | |
334 | | template <typename T, typename = void> |
335 | | class Adder : public Reducer<T, detail::AddTo<T>, detail::MinusFrom<T> > { |
336 | | public: |
337 | | typedef Reducer<T, detail::AddTo<T>, detail::MinusFrom<T> > Base; |
338 | | typedef T value_type; |
339 | | typedef typename Base::sampler_type sampler_type; |
340 | | |
341 | | Adder() : Base() {} |
342 | 0 | Adder(const butil::StringPiece& name) : Base() { |
343 | 0 | this->expose(name); |
344 | 0 | } |
345 | | Adder(const butil::StringPiece& prefix, |
346 | 0 | const butil::StringPiece& name) : Base() { |
347 | 0 | this->expose_as(prefix, name); |
348 | 0 | } |
349 | 0 | ~Adder() override { Variable::hide(); } |
350 | | }; |
351 | | |
352 | | #if WITH_BABYLON_COUNTER |
353 | | // Numerical types supported by babylon counter. |
354 | | template <typename T> |
355 | | class Adder<T, std::enable_if<std::is_constructible<babylon::GenericsConcurrentAdder<T>>::value>> |
356 | | : public detail::BabylonVariable<T, babylon::GenericsConcurrentAdder<T>, |
357 | | detail::AddTo<T>, detail::MinusFrom<T>> { |
358 | | public: |
359 | | typedef T value_type; |
360 | | private: |
361 | | typedef detail::BabylonVariable<T, babylon::GenericsConcurrentAdder<T>, |
362 | | detail::AddTo<value_type>, detail::MinusFrom<value_type>> Base; |
363 | | public: |
364 | | typedef detail::AddTo<value_type> Op; |
365 | | typedef detail::MinusFrom<value_type> InvOp; |
366 | | typedef typename Base::sampler_type sampler_type; |
367 | | |
368 | | COMMON_VARIABLE_CONSTRUCTOR(Adder); |
369 | | }; |
370 | | #endif // WITH_BABYLON_COUNTER |
371 | | |
372 | | // bvar::Maxer<int> max_value; |
373 | | // max_value << 1 << 2 << 3 << 4; |
374 | | // LOG(INFO) << max_value.get_value(); // 4 |
375 | | namespace detail { |
376 | | template <typename Tp> |
377 | | struct MaxTo { |
378 | | void operator()(Tp & lhs, |
379 | 0 | typename butil::add_cr_non_integral<Tp>::type rhs) const { |
380 | | // Use operator< as well. |
381 | 0 | if (lhs < rhs) { |
382 | 0 | lhs = rhs; |
383 | 0 | } |
384 | 0 | } |
385 | | }; |
386 | | |
387 | | class LatencyRecorderBase; |
388 | | } // namespace detail |
389 | | |
390 | | template <typename T, typename = void> |
391 | | class Maxer : public Reducer<T, detail::MaxTo<T> > { |
392 | | public: |
393 | | typedef Reducer<T, detail::MaxTo<T> > Base; |
394 | | typedef T value_type; |
395 | | typedef typename Base::sampler_type sampler_type; |
396 | | |
397 | | Maxer() : Base(std::numeric_limits<T>::min()) {} |
398 | | Maxer(const butil::StringPiece& name) |
399 | | : Base(std::numeric_limits<T>::min()) { |
400 | | this->expose(name); |
401 | | } |
402 | | Maxer(const butil::StringPiece& prefix, const butil::StringPiece& name) |
403 | | : Base(std::numeric_limits<T>::min()) { |
404 | | this->expose_as(prefix, name); |
405 | | } |
406 | 0 | ~Maxer() override { Variable::hide(); } |
407 | | |
408 | | private: |
409 | | friend class detail::LatencyRecorderBase; |
410 | | // The following private funcition a now used in LatencyRecorder, |
411 | | // it's dangerous so we don't make them public |
412 | 0 | explicit Maxer(T default_value) : Base(default_value) { |
413 | 0 | } |
414 | | Maxer(T default_value, const butil::StringPiece& prefix, |
415 | | const butil::StringPiece& name) |
416 | | : Base(default_value) { |
417 | | this->expose_as(prefix, name); |
418 | | } |
419 | | Maxer(T default_value, const butil::StringPiece& name) : Base(default_value) { |
420 | | this->expose(name); |
421 | | } |
422 | | }; |
423 | | |
424 | | #if WITH_BABYLON_COUNTER |
425 | | namespace detail { |
426 | | template <typename T> |
427 | | class ConcurrentMaxer : public babylon::GenericsConcurrentMaxer<T> { |
428 | | typedef babylon::GenericsConcurrentMaxer<T> Base; |
429 | | public: |
430 | | ConcurrentMaxer() = default; |
431 | | ConcurrentMaxer(T default_value) : _default_value(default_value) {} |
432 | | |
433 | | T value() const { |
434 | | T result; |
435 | | if (!Base::value(result)) { |
436 | | return _default_value; |
437 | | } |
438 | | return std::max(result, _default_value); |
439 | | } |
440 | | private: |
441 | | T _default_value{0}; |
442 | | }; |
443 | | } // namespace detail |
444 | | |
445 | | // Numerical types supported by babylon counter. |
446 | | template <typename T> |
447 | | class Maxer<T, std::enable_if<std::is_constructible<detail::ConcurrentMaxer<T>>::value>> |
448 | | : public detail::BabylonVariable<T, detail::ConcurrentMaxer<T>, |
449 | | detail::MaxTo<T>, detail::VoidOp> { |
450 | | public: |
451 | | typedef T value_type; |
452 | | private: |
453 | | typedef detail::BabylonVariable<T, detail::ConcurrentMaxer<T>, |
454 | | detail::MaxTo<value_type>, detail::VoidOp> Base; |
455 | | public: |
456 | | typedef detail::MaxTo<value_type> Op; |
457 | | typedef detail::VoidOp InvOp; |
458 | | typedef typename Base::sampler_type sampler_type; |
459 | | |
460 | | COMMON_VARIABLE_CONSTRUCTOR(Maxer); |
461 | | |
462 | | private: |
463 | | friend class detail::LatencyRecorderBase; |
464 | | |
465 | | Maxer(T default_value) : Base(default_value) {} |
466 | | Maxer(T default_value, const butil::StringPiece& prefix, const butil::StringPiece& name) |
467 | | : Base(default_value) { |
468 | | Variable::expose_as(prefix, name); |
469 | | } |
470 | | Maxer(T default_value, const butil::StringPiece& name) |
471 | | : Base(default_value) { |
472 | | Variable::expose(name); |
473 | | } |
474 | | }; |
475 | | #endif // WITH_BABYLON_COUNTER |
476 | | |
477 | | // bvar::Miner<int> min_value; |
478 | | // min_value << 1 << 2 << 3 << 4; |
479 | | // LOG(INFO) << min_value.get_value(); // 1 |
480 | | namespace detail { |
481 | | template <typename Tp> |
482 | | struct MinTo { |
483 | | void operator()(Tp & lhs, |
484 | | typename butil::add_cr_non_integral<Tp>::type rhs) const { |
485 | | if (rhs < lhs) { |
486 | | lhs = rhs; |
487 | | } |
488 | | } |
489 | | }; |
490 | | } // namespace detail |
491 | | |
492 | | template <typename T, typename = void> |
493 | | class Miner : public Reducer<T, detail::MinTo<T> > { |
494 | | public: |
495 | | typedef Reducer<T, detail::MinTo<T> > Base; |
496 | | typedef T value_type; |
497 | | typedef typename Base::sampler_type sampler_type; |
498 | | |
499 | | Miner() : Base(std::numeric_limits<T>::max()) {} |
500 | | Miner(const butil::StringPiece& name) |
501 | | : Base(std::numeric_limits<T>::max()) { |
502 | | this->expose(name); |
503 | | } |
504 | | Miner(const butil::StringPiece& prefix, const butil::StringPiece& name) |
505 | | : Base(std::numeric_limits<T>::max()) { |
506 | | this->expose_as(prefix, name); |
507 | | } |
508 | | ~Miner() override { Variable::hide(); } |
509 | | }; |
510 | | |
511 | | #if WITH_BABYLON_COUNTER |
512 | | // Numerical types supported by babylon counter. |
513 | | template <typename T> |
514 | | class Miner<T, std::enable_if<std::is_constructible<babylon::GenericsConcurrentMiner<T>>::value>> |
515 | | : public detail::BabylonVariable<T, babylon::GenericsConcurrentMiner<T>, |
516 | | detail::MinTo<T>, detail::VoidOp> { |
517 | | public: |
518 | | typedef T value_type; |
519 | | private: |
520 | | typedef detail::BabylonVariable<value_type, babylon::GenericsConcurrentMiner<T>, |
521 | | detail::MinTo<value_type>, detail::VoidOp> Base; |
522 | | public: |
523 | | typedef detail::MinTo<value_type> Op; |
524 | | typedef detail::VoidOp InvOp; |
525 | | typedef typename Base::sampler_type sampler_type; |
526 | | |
527 | | COMMON_VARIABLE_CONSTRUCTOR(Miner); |
528 | | }; |
529 | | #endif // WITH_BABYLON_COUNTER |
530 | | |
531 | | } // namespace bvar |
532 | | |
533 | | #endif //BVAR_REDUCER_H |