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/22 11:57:43 |
19 | |
20 | #ifndef BVAR_PASSIVE_STATUS_H |
21 | #define BVAR_PASSIVE_STATUS_H |
22 | |
23 | #include "bvar/variable.h" |
24 | #include "bvar/reducer.h" |
25 | |
26 | namespace bvar { |
27 | |
28 | // Display a updated-by-need value. This is done by passing in an user callback |
29 | // which is called to produce the value. |
30 | // Example: |
31 | // int print_number(void* arg) { |
32 | // ... |
33 | // return 5; |
34 | // } |
35 | // |
36 | // // number1 : 5 |
37 | // bvar::PassiveStatus<int> status1("number1", print_number, arg); |
38 | // |
39 | // // foo_number2 : 5 |
40 | // bvar::PassiveStatus<int> status2("Foo", "number2", print_number, arg); |
41 | template <typename Tp> |
42 | class PassiveStatus : public Variable { |
43 | public: |
44 | typedef Tp value_type; |
45 | typedef detail::ReducerSampler<PassiveStatus, Tp, detail::AddTo<Tp>, |
46 | detail::MinusFrom<Tp> > sampler_type; |
47 | struct PlaceHolderOp { |
48 | void operator()(Tp&, const Tp&) const {} |
49 | }; |
50 | static const bool ADDITIVE = (butil::is_integral<Tp>::value || |
51 | butil::is_floating_point<Tp>::value || |
52 | is_vector<Tp>::value); |
53 | class SeriesSampler : public detail::Sampler { |
54 | public: |
55 | typedef typename butil::conditional< |
56 | ADDITIVE, detail::AddTo<Tp>, PlaceHolderOp>::type Op; |
57 | explicit SeriesSampler(PassiveStatus* owner) |
58 | : _owner(owner), _vector_names(NULL), _series(Op()) {} |
59 | ~SeriesSampler() { |
60 | delete _vector_names; |
61 | } |
62 | void take_sample() override { _series.append(_owner->get_value()); } |
63 | void describe(std::ostream& os) { _series.describe(os, _vector_names); } |
64 | void set_vector_names(const std::string& names) { |
65 | if (_vector_names == NULL) { |
66 | _vector_names = new std::string; |
67 | } |
68 | *_vector_names = names; |
69 | } |
70 | private: |
71 | PassiveStatus* _owner; |
72 | std::string* _vector_names; |
73 | detail::Series<Tp, Op> _series; |
74 | }; |
75 | |
76 | public: |
77 | // NOTE: You must be very careful about lifetime of `arg' which should be |
78 | // valid during lifetime of PassiveStatus. |
79 | PassiveStatus(const butil::StringPiece& name, |
80 | Tp (*getfn)(void*), void* arg) |
81 | : _getfn(getfn) |
82 | , _arg(arg) |
83 | , _sampler(NULL) |
84 | , _series_sampler(NULL) { |
85 | expose(name); |
86 | } |
87 | |
88 | PassiveStatus(const butil::StringPiece& prefix, |
89 | const butil::StringPiece& name, |
90 | Tp (*getfn)(void*), void* arg) |
91 | : _getfn(getfn) |
92 | , _arg(arg) |
93 | , _sampler(NULL) |
94 | , _series_sampler(NULL) { |
95 | expose_as(prefix, name); |
96 | } |
97 | |
98 | PassiveStatus(Tp (*getfn)(void*), void* arg) |
99 | : _getfn(getfn) |
100 | , _arg(arg) |
101 | , _sampler(NULL) |
102 | , _series_sampler(NULL) { |
103 | } |
104 | |
105 | ~PassiveStatus() { |
106 | hide(); |
107 | if (_sampler) { |
108 | _sampler->destroy(); |
109 | _sampler = NULL; |
110 | } |
111 | if (_series_sampler) { |
112 | _series_sampler->destroy(); |
113 | _series_sampler = NULL; |
114 | } |
115 | } |
116 | |
117 | int set_vector_names(const std::string& names) { |
118 | if (_series_sampler) { |
119 | _series_sampler->set_vector_names(names); |
120 | return 0; |
121 | } |
122 | return -1; |
123 | } |
124 | |
125 | void describe(std::ostream& os, bool /*quote_string*/) const override { |
126 | os << get_value(); |
127 | } |
128 | |
129 | #ifdef BAIDU_INTERNAL |
130 | void get_value(boost::any* value) const override { |
131 | if (_getfn) { |
132 | *value = _getfn(_arg); |
133 | } else { |
134 | *value = Tp(); |
135 | } |
136 | } |
137 | #endif |
138 | |
139 | Tp get_value() const { |
140 | return (_getfn ? _getfn(_arg) : Tp()); |
141 | } |
142 | |
143 | sampler_type* get_sampler() { |
144 | if (NULL == _sampler) { |
145 | _sampler = new sampler_type(this); |
146 | _sampler->schedule(); |
147 | } |
148 | return _sampler; |
149 | } |
150 | |
151 | detail::AddTo<Tp> op() const { return detail::AddTo<Tp>(); } |
152 | detail::MinusFrom<Tp> inv_op() const { return detail::MinusFrom<Tp>(); } |
153 | |
154 | int describe_series(std::ostream& os, const SeriesOptions& options) const override { |
155 | if (_series_sampler == NULL) { |
156 | return 1; |
157 | } |
158 | if (!options.test_only) { |
159 | _series_sampler->describe(os); |
160 | } |
161 | return 0; |
162 | } |
163 | |
164 | Tp reset() { |
165 | CHECK(false) << "PassiveStatus::reset() should never be called, abort" ; |
166 | abort(); |
167 | } |
168 | |
169 | protected: |
170 | int expose_impl(const butil::StringPiece& prefix, |
171 | const butil::StringPiece& name, |
172 | DisplayFilter display_filter) override { |
173 | const int rc = Variable::expose_impl(prefix, name, display_filter); |
174 | if (ADDITIVE && |
175 | rc == 0 && |
176 | _series_sampler == NULL && |
177 | FLAGS_save_series) { |
178 | _series_sampler = new SeriesSampler(this); |
179 | _series_sampler->schedule(); |
180 | } |
181 | return rc; |
182 | } |
183 | |
184 | private: |
185 | Tp (*_getfn)(void*); |
186 | void* _arg; |
187 | sampler_type* _sampler; |
188 | SeriesSampler* _series_sampler; |
189 | }; |
190 | |
191 | // ccover g++ may complain about ADDITIVE is undefined unless it's |
192 | // explicitly declared here. |
193 | template <typename Tp> const bool PassiveStatus<Tp>::ADDITIVE; |
194 | |
195 | // Specialize std::string for using std::ostream& as a more friendly |
196 | // interface for user's callback. |
197 | template <> |
198 | class PassiveStatus<std::string> : public Variable { |
199 | public: |
200 | // NOTE: You must be very careful about lifetime of `arg' which should be |
201 | // valid during lifetime of PassiveStatus. |
202 | PassiveStatus(const butil::StringPiece& name, |
203 | void (*print)(std::ostream&, void*), void* arg) |
204 | : _print(print), _arg(arg) { |
205 | expose(name); |
206 | } |
207 | |
208 | PassiveStatus(const butil::StringPiece& prefix, |
209 | const butil::StringPiece& name, |
210 | void (*print)(std::ostream&, void*), void* arg) |
211 | : _print(print), _arg(arg) { |
212 | expose_as(prefix, name); |
213 | } |
214 | |
215 | PassiveStatus(void (*print)(std::ostream&, void*), void* arg) |
216 | : _print(print), _arg(arg) {} |
217 | |
218 | ~PassiveStatus() { |
219 | hide(); |
220 | } |
221 | |
222 | void describe(std::ostream& os, bool quote_string) const override { |
223 | if (quote_string) { |
224 | if (_print) { |
225 | os << '"'; |
226 | _print(os, _arg); |
227 | os << '"'; |
228 | } else { |
229 | os << "\"null\"" ; |
230 | } |
231 | } else { |
232 | if (_print) { |
233 | _print(os, _arg); |
234 | } else { |
235 | os << "null" ; |
236 | } |
237 | } |
238 | } |
239 | |
240 | private: |
241 | void (*_print)(std::ostream&, void*); |
242 | void* _arg; |
243 | }; |
244 | |
245 | template <typename Tp> |
246 | class BasicPassiveStatus : public PassiveStatus<Tp> { |
247 | public: |
248 | BasicPassiveStatus(const butil::StringPiece& name, |
249 | Tp (*getfn)(void*), void* arg) |
250 | : PassiveStatus<Tp>(name, getfn, arg) {} |
251 | |
252 | BasicPassiveStatus(const butil::StringPiece& prefix, |
253 | const butil::StringPiece& name, |
254 | Tp (*getfn)(void*), void* arg) |
255 | : PassiveStatus<Tp>(prefix, name, getfn, arg) {} |
256 | |
257 | BasicPassiveStatus(Tp (*getfn)(void*), void* arg) |
258 | : PassiveStatus<Tp>(getfn, arg) {} |
259 | }; |
260 | |
261 | template <> |
262 | class BasicPassiveStatus<std::string> : public PassiveStatus<std::string> { |
263 | public: |
264 | BasicPassiveStatus(const butil::StringPiece& name, |
265 | void (*print)(std::ostream&, void*), void* arg) |
266 | : PassiveStatus<std::string>(name, print, arg) {} |
267 | |
268 | BasicPassiveStatus(const butil::StringPiece& prefix, |
269 | const butil::StringPiece& name, |
270 | void (*print)(std::ostream&, void*), void* arg) |
271 | : PassiveStatus<std::string>(prefix, name, print, arg) {} |
272 | |
273 | BasicPassiveStatus(void (*print)(std::ostream&, void*), void* arg) |
274 | : PassiveStatus<std::string>(print, arg) {} |
275 | }; |
276 | |
277 | |
278 | } // namespace bvar |
279 | |
280 | #endif //BVAR_PASSIVE_STATUS_H |
281 | |