281 lines
8.4 KiB
C++
281 lines
8.4 KiB
C++
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
// Date 2014/09/22 11:57:43
|
|
|
|
#ifndef BVAR_PASSIVE_STATUS_H
|
|
#define BVAR_PASSIVE_STATUS_H
|
|
|
|
#include "bvar/variable.h"
|
|
#include "bvar/reducer.h"
|
|
|
|
namespace bvar {
|
|
|
|
// Display a updated-by-need value. This is done by passing in an user callback
|
|
// which is called to produce the value.
|
|
// Example:
|
|
// int print_number(void* arg) {
|
|
// ...
|
|
// return 5;
|
|
// }
|
|
//
|
|
// // number1 : 5
|
|
// bvar::PassiveStatus<int> status1("number1", print_number, arg);
|
|
//
|
|
// // foo_number2 : 5
|
|
// bvar::PassiveStatus<int> status2("Foo", "number2", print_number, arg);
|
|
template <typename Tp>
|
|
class PassiveStatus : public Variable {
|
|
public:
|
|
typedef Tp value_type;
|
|
typedef detail::ReducerSampler<PassiveStatus, Tp, detail::AddTo<Tp>,
|
|
detail::MinusFrom<Tp> > sampler_type;
|
|
struct PlaceHolderOp {
|
|
void operator()(Tp&, const Tp&) const {}
|
|
};
|
|
static const bool ADDITIVE = (butil::is_integral<Tp>::value ||
|
|
butil::is_floating_point<Tp>::value ||
|
|
is_vector<Tp>::value);
|
|
class SeriesSampler : public detail::Sampler {
|
|
public:
|
|
typedef typename butil::conditional<
|
|
ADDITIVE, detail::AddTo<Tp>, PlaceHolderOp>::type Op;
|
|
explicit SeriesSampler(PassiveStatus* owner)
|
|
: _owner(owner), _vector_names(NULL), _series(Op()) {}
|
|
~SeriesSampler() {
|
|
delete _vector_names;
|
|
}
|
|
void take_sample() override { _series.append(_owner->get_value()); }
|
|
void describe(std::ostream& os) { _series.describe(os, _vector_names); }
|
|
void set_vector_names(const std::string& names) {
|
|
if (_vector_names == NULL) {
|
|
_vector_names = new std::string;
|
|
}
|
|
*_vector_names = names;
|
|
}
|
|
private:
|
|
PassiveStatus* _owner;
|
|
std::string* _vector_names;
|
|
detail::Series<Tp, Op> _series;
|
|
};
|
|
|
|
public:
|
|
// NOTE: You must be very careful about lifetime of `arg' which should be
|
|
// valid during lifetime of PassiveStatus.
|
|
PassiveStatus(const butil::StringPiece& name,
|
|
Tp (*getfn)(void*), void* arg)
|
|
: _getfn(getfn)
|
|
, _arg(arg)
|
|
, _sampler(NULL)
|
|
, _series_sampler(NULL) {
|
|
expose(name);
|
|
}
|
|
|
|
PassiveStatus(const butil::StringPiece& prefix,
|
|
const butil::StringPiece& name,
|
|
Tp (*getfn)(void*), void* arg)
|
|
: _getfn(getfn)
|
|
, _arg(arg)
|
|
, _sampler(NULL)
|
|
, _series_sampler(NULL) {
|
|
expose_as(prefix, name);
|
|
}
|
|
|
|
PassiveStatus(Tp (*getfn)(void*), void* arg)
|
|
: _getfn(getfn)
|
|
, _arg(arg)
|
|
, _sampler(NULL)
|
|
, _series_sampler(NULL) {
|
|
}
|
|
|
|
~PassiveStatus() {
|
|
hide();
|
|
if (_sampler) {
|
|
_sampler->destroy();
|
|
_sampler = NULL;
|
|
}
|
|
if (_series_sampler) {
|
|
_series_sampler->destroy();
|
|
_series_sampler = NULL;
|
|
}
|
|
}
|
|
|
|
int set_vector_names(const std::string& names) {
|
|
if (_series_sampler) {
|
|
_series_sampler->set_vector_names(names);
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void describe(std::ostream& os, bool /*quote_string*/) const override {
|
|
os << get_value();
|
|
}
|
|
|
|
#ifdef BAIDU_INTERNAL
|
|
void get_value(boost::any* value) const override {
|
|
if (_getfn) {
|
|
*value = _getfn(_arg);
|
|
} else {
|
|
*value = Tp();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Tp get_value() const {
|
|
return (_getfn ? _getfn(_arg) : Tp());
|
|
}
|
|
|
|
sampler_type* get_sampler() {
|
|
if (NULL == _sampler) {
|
|
_sampler = new sampler_type(this);
|
|
_sampler->schedule();
|
|
}
|
|
return _sampler;
|
|
}
|
|
|
|
detail::AddTo<Tp> op() const { return detail::AddTo<Tp>(); }
|
|
detail::MinusFrom<Tp> inv_op() const { return detail::MinusFrom<Tp>(); }
|
|
|
|
int describe_series(std::ostream& os, const SeriesOptions& options) const override {
|
|
if (_series_sampler == NULL) {
|
|
return 1;
|
|
}
|
|
if (!options.test_only) {
|
|
_series_sampler->describe(os);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Tp reset() {
|
|
CHECK(false) << "PassiveStatus::reset() should never be called, abort";
|
|
abort();
|
|
}
|
|
|
|
protected:
|
|
int expose_impl(const butil::StringPiece& prefix,
|
|
const butil::StringPiece& name,
|
|
DisplayFilter display_filter) override {
|
|
const int rc = Variable::expose_impl(prefix, name, display_filter);
|
|
if (ADDITIVE &&
|
|
rc == 0 &&
|
|
_series_sampler == NULL &&
|
|
FLAGS_save_series) {
|
|
_series_sampler = new SeriesSampler(this);
|
|
_series_sampler->schedule();
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
private:
|
|
Tp (*_getfn)(void*);
|
|
void* _arg;
|
|
sampler_type* _sampler;
|
|
SeriesSampler* _series_sampler;
|
|
};
|
|
|
|
// ccover g++ may complain about ADDITIVE is undefined unless it's
|
|
// explicitly declared here.
|
|
template <typename Tp> const bool PassiveStatus<Tp>::ADDITIVE;
|
|
|
|
// Specialize std::string for using std::ostream& as a more friendly
|
|
// interface for user's callback.
|
|
template <>
|
|
class PassiveStatus<std::string> : public Variable {
|
|
public:
|
|
// NOTE: You must be very careful about lifetime of `arg' which should be
|
|
// valid during lifetime of PassiveStatus.
|
|
PassiveStatus(const butil::StringPiece& name,
|
|
void (*print)(std::ostream&, void*), void* arg)
|
|
: _print(print), _arg(arg) {
|
|
expose(name);
|
|
}
|
|
|
|
PassiveStatus(const butil::StringPiece& prefix,
|
|
const butil::StringPiece& name,
|
|
void (*print)(std::ostream&, void*), void* arg)
|
|
: _print(print), _arg(arg) {
|
|
expose_as(prefix, name);
|
|
}
|
|
|
|
PassiveStatus(void (*print)(std::ostream&, void*), void* arg)
|
|
: _print(print), _arg(arg) {}
|
|
|
|
~PassiveStatus() {
|
|
hide();
|
|
}
|
|
|
|
void describe(std::ostream& os, bool quote_string) const override {
|
|
if (quote_string) {
|
|
if (_print) {
|
|
os << '"';
|
|
_print(os, _arg);
|
|
os << '"';
|
|
} else {
|
|
os << "\"null\"";
|
|
}
|
|
} else {
|
|
if (_print) {
|
|
_print(os, _arg);
|
|
} else {
|
|
os << "null";
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
void (*_print)(std::ostream&, void*);
|
|
void* _arg;
|
|
};
|
|
|
|
template <typename Tp>
|
|
class BasicPassiveStatus : public PassiveStatus<Tp> {
|
|
public:
|
|
BasicPassiveStatus(const butil::StringPiece& name,
|
|
Tp (*getfn)(void*), void* arg)
|
|
: PassiveStatus<Tp>(name, getfn, arg) {}
|
|
|
|
BasicPassiveStatus(const butil::StringPiece& prefix,
|
|
const butil::StringPiece& name,
|
|
Tp (*getfn)(void*), void* arg)
|
|
: PassiveStatus<Tp>(prefix, name, getfn, arg) {}
|
|
|
|
BasicPassiveStatus(Tp (*getfn)(void*), void* arg)
|
|
: PassiveStatus<Tp>(getfn, arg) {}
|
|
};
|
|
|
|
template <>
|
|
class BasicPassiveStatus<std::string> : public PassiveStatus<std::string> {
|
|
public:
|
|
BasicPassiveStatus(const butil::StringPiece& name,
|
|
void (*print)(std::ostream&, void*), void* arg)
|
|
: PassiveStatus<std::string>(name, print, arg) {}
|
|
|
|
BasicPassiveStatus(const butil::StringPiece& prefix,
|
|
const butil::StringPiece& name,
|
|
void (*print)(std::ostream&, void*), void* arg)
|
|
: PassiveStatus<std::string>(prefix, name, print, arg) {}
|
|
|
|
BasicPassiveStatus(void (*print)(std::ostream&, void*), void* arg)
|
|
: PassiveStatus<std::string>(print, arg) {}
|
|
};
|
|
|
|
|
|
} // namespace bvar
|
|
|
|
#endif //BVAR_PASSIVE_STATUS_H
|