blob: eb4900d848eeb93685c19e655261dcf0e4973717 [file] [log] [blame]
// 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