Coverage Report

Created: 2025-09-17 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/brpc/src/butil/iobuf_profiler.h
Line
Count
Source
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
#ifndef BIGO_BRPC_IOBUF_PROFILER_H
19
#define BIGO_BRPC_IOBUF_PROFILER_H
20
21
#include <unordered_map>
22
#include <unordered_set>
23
#include "butil/iobuf.h"
24
#include "butil/object_pool.h"
25
#include "butil/threading/simple_thread.h"
26
#include "butil/threading/simple_thread.h"
27
#include "butil/memory/singleton.h"
28
#include "butil/containers/flat_map.h"
29
#include "butil/containers/mpsc_queue.h"
30
31
namespace butil {
32
33
struct IOBufSample;
34
typedef std::shared_ptr<IOBufSample> IOBufRefSampleSharedPtr;
35
36
struct IOBufSample {
37
    IOBufSample* next;
38
    IOBuf::Block* block;
39
    int64_t count; // // reference count of the block.
40
    void* stack[28]; // backtrace.
41
    int nframes; // num of frames in stack.
42
43
0
    static IOBufSample* New() {
44
0
        return get_object<IOBufSample>();
45
0
    }
46
47
    static IOBufSample* Copy(IOBufSample* ref);
48
    static IOBufRefSampleSharedPtr CopyAndSharedWithDestroyer(IOBufSample* ref);
49
0
    static void Destroy(IOBufSample* ref) {
50
0
        ref->_hash_code = 0;
51
0
        return_object(ref);
52
0
    }
53
54
    size_t stack_hash_code() const;
55
56
private:
57
friend ObjectPool<IOBufSample>;
58
59
    IOBufSample()
60
0
        : next(NULL)
61
0
        , block(NULL)
62
0
        , count(0)
63
0
        , stack{}
64
0
        , nframes(0)
65
0
        , _hash_code(0) {}
66
67
    ~IOBufSample() = default;
68
69
    mutable uint32_t _hash_code; // For combining samples with hashmap.
70
};
71
72
BAIDU_CASSERT(sizeof(IOBufSample) == 256, be_friendly_to_allocator);
73
74
namespace detail {
75
// Functor to compare IOBufRefSample.
76
template <typename T>
77
struct IOBufSampleEqual {
78
0
    bool operator()(const T& c1, const T& c2) const {
79
0
        return c1->stack_hash_code() ==c2->stack_hash_code() &&
80
0
            c1->nframes == c2->nframes &&
81
0
            memcmp(c1->stack, c2->stack, sizeof(void*) * c1->nframes) == 0;
82
0
    }
Unexecuted instantiation: butil::detail::IOBufSampleEqual<butil::IOBufSample*>::operator()(butil::IOBufSample* const&, butil::IOBufSample* const&) const
Unexecuted instantiation: butil::detail::IOBufSampleEqual<std::shared_ptr<butil::IOBufSample> >::operator()(std::shared_ptr<butil::IOBufSample> const&, std::shared_ptr<butil::IOBufSample> const&) const
83
};
84
85
// Functor to hash IOBufRefSample.
86
template <typename T>
87
struct IOBufSampleHash {
88
0
    size_t operator()(const T& c) const {
89
0
        return c->stack_hash_code();
90
0
    }
Unexecuted instantiation: butil::detail::IOBufSampleHash<butil::IOBufSample*>::operator()(butil::IOBufSample* const&) const
Unexecuted instantiation: butil::detail::IOBufSampleHash<std::shared_ptr<butil::IOBufSample> >::operator()(std::shared_ptr<butil::IOBufSample> const&) const
91
};
92
93
struct Destroyer {
94
0
    void operator()(IOBufSample* ref) const {
95
0
        if (ref) {
96
0
            IOBufSample::Destroy(ref);
97
0
        }
98
0
    }
99
};
100
}
101
102
class IOBufProfiler : public butil::SimpleThread {
103
public:
104
    static IOBufProfiler* GetInstance();
105
106
    // Submit the IOBuf sample along with stacktrace.
107
    void Submit(IOBufSample* s);
108
    // Dump IOBuf sample to map.
109
    void Dump(IOBufSample* s);
110
    // Write buffered data into resulting file.
111
    void Flush2Disk(const char* filename);
112
113
    void StopAndJoin();
114
115
private:
116
    friend struct DefaultSingletonTraits<IOBufProfiler>;
117
118
    typedef butil::FlatMap<IOBufSample*,
119
                           IOBufRefSampleSharedPtr,
120
                           detail::IOBufSampleHash<IOBufSample*>,
121
                           detail::IOBufSampleEqual<IOBufSample*>> IOBufRefMap;
122
123
    // <iobuf stack, ref count>
124
    typedef butil::FlatMap<IOBufRefSampleSharedPtr,
125
                           int64_t,
126
                           detail::IOBufSampleHash<IOBufRefSampleSharedPtr>,
127
                           detail::IOBufSampleEqual<IOBufRefSampleSharedPtr>> StackCountMap;
128
    struct BlockInfo {
129
        int64_t ref{0};
130
        StackCountMap stack_count_map;
131
    };
132
    typedef butil::FlatMap<IOBuf::Block*, BlockInfo> BlockInfoMap;
133
134
    IOBufProfiler();
135
    ~IOBufProfiler() override;
136
    DISALLOW_COPY_AND_ASSIGN(IOBufProfiler);
137
138
    void Run() override;
139
    // Consume the IOBuf sample in _sample_queue.
140
    void Consume();
141
142
    // Stop flag of IOBufProfiler.
143
    butil::atomic<bool> _stop;
144
    // IOBuf sample queue.
145
    MPSCQueue<IOBufSample*> _sample_queue;
146
147
    // Temp buf before saving the file.
148
    butil::IOBuf _disk_buf;
149
    // Combining same samples to make result smaller.
150
    IOBufRefMap _stack_map;
151
    // Record block info.
152
    BlockInfoMap _block_info_map;
153
    Mutex _mutex;
154
155
    // Sleep when `_sample_queue' is empty.
156
    uint32_t _sleep_ms;
157
    static const uint32_t MIN_SLEEP_MS;
158
    static const uint32_t MAX_SLEEP_MS;
159
};
160
161
bool IsIOBufProfilerEnabled();
162
bool IsIOBufProfilerSamplable();
163
164
void SubmitIOBufSample(IOBuf::Block* block, int64_t ref);
165
166
bool IOBufProfilerFlush(const char* filename);
167
168
}
169
#endif //BIGO_BRPC_IOBUF_PROFILER_H