Coverage Report

Created: 2025-08-05 06:45

/src/brpc/src/bvar/detail/sampler.h
Line
Count
Source (jump to first uncovered line)
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: Tue Jul 28 18:15:57 CST 2015
19
20
#ifndef  BVAR_DETAIL_SAMPLER_H
21
#define  BVAR_DETAIL_SAMPLER_H
22
23
#include <vector>
24
#include "butil/containers/linked_list.h"// LinkNode
25
#include "butil/scoped_lock.h"           // BAIDU_SCOPED_LOCK
26
#include "butil/logging.h"               // LOG()
27
#include "butil/containers/bounded_queue.h"// BoundedQueue
28
#include "butil/type_traits.h"           // is_same
29
#include "butil/time.h"                  // gettimeofday_us
30
#include "butil/class_name.h"
31
32
namespace bvar {
33
namespace detail {
34
35
template <typename T>
36
struct Sample {
37
    T data;
38
    int64_t time_us;
39
40
0
    Sample() : data(), time_us(0) {}
Unexecuted instantiation: bvar::detail::Sample<bvar::detail::PercentileSamples<254ul> >::Sample()
Unexecuted instantiation: bvar::detail::Sample<bvar::Stat>::Sample()
Unexecuted instantiation: bvar::detail::Sample<double>::Sample()
Unexecuted instantiation: bvar::detail::Sample<unsigned long>::Sample()
Unexecuted instantiation: bvar::detail::Sample<int>::Sample()
Unexecuted instantiation: bvar::detail::Sample<long>::Sample()
41
    Sample(const T& data2, int64_t time2) : data(data2), time_us(time2) {}  
42
};
43
44
// The base class for all samplers whose take_sample() are called periodically.
45
class Sampler : public butil::LinkNode<Sampler> {
46
public:
47
    Sampler();
48
        
49
    // This function will be called every second(approximately) in a
50
    // dedicated thread if schedule() is called.
51
    virtual void take_sample() = 0;
52
53
    // Register this sampler globally so that take_sample() will be called
54
    // periodically.
55
    void schedule();
56
57
    // Call this function instead of delete to destroy the sampler. Deletion
58
    // of the sampler may be delayed for seconds.
59
    void destroy();
60
        
61
protected:
62
    virtual ~Sampler();
63
    
64
friend class SamplerCollector;
65
    bool _used;
66
    // Sync destroy() and take_sample().
67
    butil::Mutex _mutex;
68
};
69
70
// Representing a non-existing operator so that we can test
71
// is_same<Op, VoidOp>::value to write code for different branches.
72
// The false branch should be removed by compiler at compile-time.
73
struct VoidOp {
74
    template <typename T>
75
0
    T operator()(const T&, const T&) const {
76
0
        CHECK(false) << "This function should never be called, abort";
77
0
        abort();
78
0
    }
Unexecuted instantiation: long bvar::detail::VoidOp::operator()<long>(long const&, long const&) const
Unexecuted instantiation: bvar::detail::PercentileSamples<254ul> bvar::detail::VoidOp::operator()<bvar::detail::PercentileSamples<254ul> >(bvar::detail::PercentileSamples<254ul> const&, bvar::detail::PercentileSamples<254ul> const&) const
79
};
80
81
// The sampler for reducer-alike variables.
82
// The R should have following methods:
83
//  - T reset();
84
//  - T get_value();
85
//  - Op op();
86
//  - InvOp inv_op();
87
template <typename R, typename T, typename Op, typename InvOp>
88
class ReducerSampler : public Sampler {
89
public:
90
    static const time_t MAX_SECONDS_LIMIT = 3600;
91
92
    explicit ReducerSampler(R* reducer)
93
0
        : _reducer(reducer)
94
0
        , _window_size(1) {
95
        
96
        // Invoked take_sample at begining so the value of the first second
97
        // would not be ignored
98
0
        take_sample();
99
0
    }
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<double>, double, bvar::detail::AddTo<double>, bvar::detail::MinusFrom<double> >::ReducerSampler(bvar::PassiveStatus<double>*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<unsigned long>, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::ReducerSampler(bvar::PassiveStatus<unsigned long>*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >, int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >::ReducerSampler(bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::ReducerSampler(bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<long>, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::ReducerSampler(bvar::PassiveStatus<long>*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::IntRecorder, bvar::Stat, bvar::IntRecorder::AddStat, bvar::IntRecorder::MinusStat>::ReducerSampler(bvar::IntRecorder*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::ReducerSampler(bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::detail::Percentile, bvar::detail::PercentileSamples<254ul>, bvar::detail::Percentile::AddPercentileSamples, bvar::detail::VoidOp>::ReducerSampler(bvar::detail::Percentile*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::ReducerSampler(bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >*)
100
0
    ~ReducerSampler() {}
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<double>, double, bvar::detail::AddTo<double>, bvar::detail::MinusFrom<double> >::~ReducerSampler()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<unsigned long>, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::~ReducerSampler()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >, int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >::~ReducerSampler()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::~ReducerSampler()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<long>, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::~ReducerSampler()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::IntRecorder, bvar::Stat, bvar::IntRecorder::AddStat, bvar::IntRecorder::MinusStat>::~ReducerSampler()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::~ReducerSampler()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::detail::Percentile, bvar::detail::PercentileSamples<254ul>, bvar::detail::Percentile::AddPercentileSamples, bvar::detail::VoidOp>::~ReducerSampler()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::~ReducerSampler()
101
102
0
    void take_sample() override {
103
        // Make _q ready.
104
        // If _window_size is larger than what _q can hold, e.g. a larger
105
        // Window<> is created after running of sampler, make _q larger.
106
0
        if ((size_t)_window_size + 1 > _q.capacity()) {
107
0
            const size_t new_cap =
108
0
                std::max(_q.capacity() * 2, (size_t)_window_size + 1);
109
0
            const size_t memsize = sizeof(Sample<T>) * new_cap;
110
0
            void* mem = malloc(memsize);
111
0
            if (NULL == mem) {
112
0
                return;
113
0
            }
114
0
            butil::BoundedQueue<Sample<T> > new_q(
115
0
                mem, memsize, butil::OWNS_STORAGE);
116
0
            Sample<T> tmp;
117
0
            while (_q.pop(&tmp)) {
118
0
                new_q.push(tmp);
119
0
            }
120
0
            new_q.swap(_q);
121
0
        }
122
123
0
        Sample<T> latest;
124
0
        if (butil::is_same<InvOp, VoidOp>::value) {
125
            // The operator can't be inversed.
126
            // We reset the reducer and save the result as a sample.
127
            // Suming up samples gives the result within a window.
128
            // In this case, get_value() of _reducer gives wrong answer and
129
            // should not be called.
130
0
            latest.data = _reducer->reset();
131
0
        } else {
132
            // The operator can be inversed.
133
            // We save the result as a sample.
134
            // Inversed operation between latest and oldest sample within a
135
            // window gives result.
136
            // get_value() of _reducer can still be called.
137
0
            latest.data = _reducer->get_value();
138
0
        }
139
0
        latest.time_us = butil::gettimeofday_us();
140
0
        _q.elim_push(latest);
141
0
    }
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::IntRecorder, bvar::Stat, bvar::IntRecorder::AddStat, bvar::IntRecorder::MinusStat>::take_sample()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::detail::Percentile, bvar::detail::PercentileSamples<254ul>, bvar::detail::Percentile::AddPercentileSamples, bvar::detail::VoidOp>::take_sample()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<double>, double, bvar::detail::AddTo<double>, bvar::detail::MinusFrom<double> >::take_sample()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<unsigned long>, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::take_sample()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >, int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >::take_sample()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::take_sample()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<long>, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::take_sample()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::take_sample()
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::take_sample()
142
143
0
    bool get_value(time_t window_size, Sample<T>* result) {
144
0
        if (window_size <= 0) {
145
0
            LOG(FATAL) << "Invalid window_size=" << window_size;
146
0
            return false;
147
0
        }
148
0
        BAIDU_SCOPED_LOCK(_mutex);
149
0
        if (_q.size() <= 1UL) {
150
            // We need more samples to get reasonable result.
151
0
            return false;
152
0
        }
153
0
        Sample<T>* oldest = _q.bottom(window_size);
154
0
        if (NULL == oldest) {
155
0
            oldest = _q.top();
156
0
        }
157
0
        Sample<T>* latest = _q.bottom();
158
0
        DCHECK(latest != oldest);
159
0
        if (butil::is_same<InvOp, VoidOp>::value) {
160
            // No inverse op. Sum up all samples within the window.
161
0
            result->data = latest->data;
162
0
            for (int i = 1; true; ++i) {
163
0
                Sample<T>* e = _q.bottom(i);
164
0
                if (e == oldest) {
165
0
                    break;
166
0
                }
167
0
                _reducer->op()(result->data, e->data);
168
0
            }
169
0
        } else {
170
            // Diff the latest and oldest sample within the window.
171
0
            result->data = latest->data;
172
0
            _reducer->inv_op()(result->data, oldest->data);
173
0
        }
174
0
        result->time_us = latest->time_us - oldest->time_us;
175
0
        return true;
176
0
    }
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::IntRecorder, bvar::Stat, bvar::IntRecorder::AddStat, bvar::IntRecorder::MinusStat>::get_value(long, bvar::detail::Sample<bvar::Stat>*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::get_value(long, bvar::detail::Sample<long>*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::detail::Percentile, bvar::detail::PercentileSamples<254ul>, bvar::detail::Percentile::AddPercentileSamples, bvar::detail::VoidOp>::get_value(long, bvar::detail::Sample<bvar::detail::PercentileSamples<254ul> >*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<double>, double, bvar::detail::AddTo<double>, bvar::detail::MinusFrom<double> >::get_value(long, bvar::detail::Sample<double>*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<unsigned long>, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::get_value(long, bvar::detail::Sample<unsigned long>*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >, int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >::get_value(long, bvar::detail::Sample<int>*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::get_value(long, bvar::detail::Sample<long>*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<long>, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::get_value(long, bvar::detail::Sample<long>*)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::get_value(long, bvar::detail::Sample<unsigned long>*)
177
178
    // Change the time window which can only go larger.
179
0
    int set_window_size(time_t window_size) {
180
0
        if (window_size <= 0 || window_size > MAX_SECONDS_LIMIT) {
181
0
            LOG(ERROR) << "Invalid window_size=" << window_size;
182
0
            return -1;
183
0
        }
184
0
        BAIDU_SCOPED_LOCK(_mutex);
185
0
        if (window_size > _window_size) {
186
0
            _window_size = window_size;
187
0
        }
188
0
        return 0;
189
0
    }
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<double>, double, bvar::detail::AddTo<double>, bvar::detail::MinusFrom<double> >::set_window_size(long)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<unsigned long>, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::set_window_size(long)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >, int, bvar::detail::AddTo<int>, bvar::detail::MinusFrom<int> >::set_window_size(long)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::set_window_size(long)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::PassiveStatus<long>, long, bvar::detail::AddTo<long>, bvar::detail::MinusFrom<long> >::set_window_size(long)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::IntRecorder, bvar::Stat, bvar::IntRecorder::AddStat, bvar::IntRecorder::MinusStat>::set_window_size(long)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>, long, bvar::detail::MaxTo<long>, bvar::detail::VoidOp>::set_window_size(long)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::detail::Percentile, bvar::detail::PercentileSamples<254ul>, bvar::detail::Percentile::AddPercentileSamples, bvar::detail::VoidOp>::set_window_size(long)
Unexecuted instantiation: bvar::detail::ReducerSampler<bvar::Reducer<unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >, unsigned long, bvar::detail::AddTo<unsigned long>, bvar::detail::MinusFrom<unsigned long> >::set_window_size(long)
190
191
0
    void get_samples(std::vector<T> *samples, time_t window_size) {
192
0
        if (window_size <= 0) {
193
0
            LOG(FATAL) << "Invalid window_size=" << window_size;
194
0
            return;
195
0
        }
196
0
        BAIDU_SCOPED_LOCK(_mutex);
197
0
        if (_q.size() <= 1) {
198
            // We need more samples to get reasonable result.
199
0
            return;
200
0
        }
201
0
        Sample<T>* oldest = _q.bottom(window_size);
202
0
        if (NULL == oldest) {
203
0
            oldest = _q.top();
204
0
        }
205
0
        for (int i = 1; true; ++i) {
206
0
            Sample<T>* e = _q.bottom(i);
207
0
            if (e == oldest) {
208
0
                break;
209
0
            }
210
0
            samples->push_back(e->data);
211
0
        }
212
0
    }
213
214
private:
215
    R* _reducer;
216
    time_t _window_size;
217
    butil::BoundedQueue<Sample<T> > _q;
218
};
219
220
}  // namespace detail
221
}  // namespace bvar
222
223
#endif  // BVAR_DETAIL_SAMPLER_H