| // 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 |