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
26namespace 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);
41template <typename Tp>
42class PassiveStatus : public Variable {
43public:
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
76public:
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
169protected:
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
184private:
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.
193template <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.
197template <>
198class PassiveStatus<std::string> : public Variable {
199public:
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
240private:
241 void (*_print)(std::ostream&, void*);
242 void* _arg;
243};
244
245template <typename Tp>
246class BasicPassiveStatus : public PassiveStatus<Tp> {
247public:
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
261template <>
262class BasicPassiveStatus<std::string> : public PassiveStatus<std::string> {
263public:
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