Coverage Report

Created: 2024-11-18 12:21

/root/doris/be/src/util/debug_points.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
#pragma once
19
20
#include <any>
21
#include <atomic>
22
#include <boost/lexical_cast.hpp>
23
#include <chrono>
24
#include <functional>
25
#include <map>
26
#include <memory>
27
#include <thread>
28
#include <type_traits>
29
30
#include "common/compiler_util.h"
31
#include "common/config.h"
32
#include "fmt/format.h"
33
34
// more usage can see 'util/debug_points_test.cpp'
35
// using {} around code, to avoid duplicate variable name
36
#define DBUG_EXECUTE_IF(debug_point_name, code)                               \
37
85.5k
    if (UNLIKELY(config::enable_debug_points)) {                              \
38
69.1k
        auto dp = DebugPoints::instance()->get_debug_point(debug_point_name); \
39
69.1k
        if (dp) {                                                             \
40
14
            [[maybe_unused]] auto DP_NAME = debug_point_name;                 \
41
36
            { code; }                                                         \
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN34InvertedIndexColumnWriterEmptyImpl4initEv
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN34InvertedIndexColumnWriterEmptyImpl10add_valuesENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPKvm
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN34InvertedIndexColumnWriterEmptyImpl16add_array_valuesEmPKNS_15CollectionValueEm
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN34InvertedIndexColumnWriterEmptyImpl16add_array_valuesEmPKvPKhS6_m
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN34InvertedIndexColumnWriterEmptyImpl9add_nullsEj
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN34InvertedIndexColumnWriterEmptyImpl15add_array_nullsEj
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN34InvertedIndexColumnWriterEmptyImpl6finishEv
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvENK34InvertedIndexColumnWriterEmptyImpl4sizeEv
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvENK34InvertedIndexColumnWriterEmptyImpl9file_sizeEv
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN34InvertedIndexColumnWriterEmptyImpl14close_on_errorEv
42
0
        }                                                                     \
43
69.1k
    }
44
45
// define some common debug actions
46
// usage example: DBUG_EXECUTE_IF("xxx", DBUG_BLOCK);
47
#define DBUG_BLOCK                                                      \
48
    {                                                                   \
49
        LOG(INFO) << "start debug block " << DP_NAME;                   \
50
        while (DebugPoints::instance()->is_enable(DP_NAME)) {           \
51
            std::this_thread::sleep_for(std::chrono::milliseconds(10)); \
52
        }                                                               \
53
        LOG(INFO) << "end debug block " << DP_NAME;                     \
54
    }
55
56
// DBUG_RUN_CALLBACK is usually use in be ut, to exchange local variable between the injected code and callback code.
57
// usage example: DBUG_EXECUTE_IF("xxx", DBUG_RUN_CALLBACK(yyy,...));
58
#define DBUG_RUN_CALLBACK(...) \
59
    { dp->execute_callback(__VA_ARGS__); }
60
61
// example of debug point with callback.
62
//
63
// void demo_callback() {
64
//     int a = 0;
65
//
66
//     DBUG_EXECUTE_IF("set_a", DBUG_RUN_CALLBACK(&a));
67
//     DBUG_EXECUTE_IF("get_a", DBUG_RUN_CALLBACK(a));
68
// }
69
//
70
// TEST(DebugPointsTest, Callback) {
71
//     config::enable_debug_points = true;
72
//     DebugPoints::instance()->clear();
73
//
74
//     int got_a = 0;
75
//
76
//     std::function<void(int*)> set_handler = [](int* a) { *a = 1000; };
77
//     std::function<void(int)> get_handler = [&got_a](int a) { got_a = a; };
78
//     DebugPoints::instance()->add_with_callback("set_a", set_handler);
79
//     DebugPoints::instance()->add_with_callback("get_a", get_handler);
80
//
81
//     demo_callback();
82
//
83
//     EXPECT_EQ(1000, got_a);
84
// }
85
86
namespace doris {
87
88
struct DebugPoint {
89
    std::atomic<int64_t> execute_num {0};
90
    int64_t execute_limit = -1;
91
    int64_t expire_ms = -1;
92
93
    std::map<std::string, std::string> params;
94
95
    // Usually `callback` use in be ut, to exchange local variable between callback code and injected code,
96
    // or change with different injected handlers.
97
    // test/util/debug_points_test.cpp#Callback give a example.
98
    std::any callback;
99
100
    template <typename T>
101
17
    T param(const std::string& key, T default_value = T()) {
102
17
        auto it = params.find(key);
103
17
        if (it == params.end()) {
104
4
            return default_value;
105
4
        }
106
13
        if constexpr (std::is_same_v<T, bool>) {
107
11
            if (it->second == "true") {
108
1
                return true;
109
1
            }
110
1
            if (it->second == "false") {
111
1
                return false;
112
1
            }
113
0
            return boost::lexical_cast<T>(it->second);
114
11
        } else if constexpr (std::is_arithmetic_v<T>) {
115
4
            return boost::lexical_cast<T>(it->second);
116
4
        } else if constexpr (std::is_same_v<T, const char*>) {
117
3
            return it->second.c_str();
118
3
        } else {
119
3
            static_assert(std::is_same_v<T, std::string>);
120
3
            return it->second;
121
3
        }
122
13
    }
_ZN5doris10DebugPoint5paramIiEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
101
5
    T param(const std::string& key, T default_value = T()) {
102
5
        auto it = params.find(key);
103
5
        if (it == params.end()) {
104
1
            return default_value;
105
1
        }
106
4
        if constexpr (std::is_same_v<T, bool>) {
107
4
            if (it->second == "true") {
108
4
                return true;
109
4
            }
110
4
            if (it->second == "false") {
111
4
                return false;
112
4
            }
113
4
            return boost::lexical_cast<T>(it->second);
114
4
        } else if constexpr (std::is_arithmetic_v<T>) {
115
4
            return boost::lexical_cast<T>(it->second);
116
4
        } else if constexpr (std::is_same_v<T, const char*>) {
117
4
            return it->second.c_str();
118
4
        } else {
119
4
            static_assert(std::is_same_v<T, std::string>);
120
4
            return it->second;
121
4
        }
122
4
    }
_ZN5doris10DebugPoint5paramINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEET_RKS7_S8_
Line
Count
Source
101
3
    T param(const std::string& key, T default_value = T()) {
102
3
        auto it = params.find(key);
103
3
        if (it == params.end()) {
104
0
            return default_value;
105
0
        }
106
3
        if constexpr (std::is_same_v<T, bool>) {
107
3
            if (it->second == "true") {
108
3
                return true;
109
3
            }
110
3
            if (it->second == "false") {
111
3
                return false;
112
3
            }
113
3
            return boost::lexical_cast<T>(it->second);
114
3
        } else if constexpr (std::is_arithmetic_v<T>) {
115
3
            return boost::lexical_cast<T>(it->second);
116
3
        } else if constexpr (std::is_same_v<T, const char*>) {
117
3
            return it->second.c_str();
118
3
        } else {
119
3
            static_assert(std::is_same_v<T, std::string>);
120
3
            return it->second;
121
3
        }
122
3
    }
_ZN5doris10DebugPoint5paramIPKcEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES4_
Line
Count
Source
101
2
    T param(const std::string& key, T default_value = T()) {
102
2
        auto it = params.find(key);
103
2
        if (it == params.end()) {
104
1
            return default_value;
105
1
        }
106
1
        if constexpr (std::is_same_v<T, bool>) {
107
1
            if (it->second == "true") {
108
1
                return true;
109
1
            }
110
1
            if (it->second == "false") {
111
1
                return false;
112
1
            }
113
1
            return boost::lexical_cast<T>(it->second);
114
1
        } else if constexpr (std::is_arithmetic_v<T>) {
115
1
            return boost::lexical_cast<T>(it->second);
116
1
        } else if constexpr (std::is_same_v<T, const char*>) {
117
1
            return it->second.c_str();
118
1
        } else {
119
1
            static_assert(std::is_same_v<T, std::string>);
120
1
            return it->second;
121
1
        }
122
1
    }
_ZN5doris10DebugPoint5paramIdEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
101
3
    T param(const std::string& key, T default_value = T()) {
102
3
        auto it = params.find(key);
103
3
        if (it == params.end()) {
104
0
            return default_value;
105
0
        }
106
3
        if constexpr (std::is_same_v<T, bool>) {
107
3
            if (it->second == "true") {
108
3
                return true;
109
3
            }
110
3
            if (it->second == "false") {
111
3
                return false;
112
3
            }
113
3
            return boost::lexical_cast<T>(it->second);
114
3
        } else if constexpr (std::is_arithmetic_v<T>) {
115
3
            return boost::lexical_cast<T>(it->second);
116
3
        } else if constexpr (std::is_same_v<T, const char*>) {
117
3
            return it->second.c_str();
118
3
        } else {
119
3
            static_assert(std::is_same_v<T, std::string>);
120
3
            return it->second;
121
3
        }
122
3
    }
_ZN5doris10DebugPoint5paramIbEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
101
2
    T param(const std::string& key, T default_value = T()) {
102
2
        auto it = params.find(key);
103
2
        if (it == params.end()) {
104
0
            return default_value;
105
0
        }
106
2
        if constexpr (std::is_same_v<T, bool>) {
107
2
            if (it->second == "true") {
108
1
                return true;
109
1
            }
110
1
            if (it->second == "false") {
111
1
                return false;
112
1
            }
113
0
            return boost::lexical_cast<T>(it->second);
114
1
        } else if constexpr (std::is_arithmetic_v<T>) {
115
2
            return boost::lexical_cast<T>(it->second);
116
2
        } else if constexpr (std::is_same_v<T, const char*>) {
117
2
            return it->second.c_str();
118
2
        } else {
119
2
            static_assert(std::is_same_v<T, std::string>);
120
2
            return it->second;
121
2
        }
122
2
    }
_ZN5doris10DebugPoint5paramIlEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
101
2
    T param(const std::string& key, T default_value = T()) {
102
2
        auto it = params.find(key);
103
2
        if (it == params.end()) {
104
2
            return default_value;
105
2
        }
106
0
        if constexpr (std::is_same_v<T, bool>) {
107
0
            if (it->second == "true") {
108
0
                return true;
109
0
            }
110
0
            if (it->second == "false") {
111
0
                return false;
112
0
            }
113
0
            return boost::lexical_cast<T>(it->second);
114
0
        } else if constexpr (std::is_arithmetic_v<T>) {
115
0
            return boost::lexical_cast<T>(it->second);
116
0
        } else if constexpr (std::is_same_v<T, const char*>) {
117
0
            return it->second.c_str();
118
0
        } else {
119
0
            static_assert(std::is_same_v<T, std::string>);
120
0
            return it->second;
121
0
        }
122
0
    }
123
124
    template <typename... ARGS>
125
2
    void execute_callback(ARGS... args) {
126
2
        if (!callback.has_value()) {
127
0
            throw std::invalid_argument("No set callback");
128
0
        }
129
130
2
        auto func = std::any_cast<std::function<void(ARGS...)>>(callback);
131
2
        func(args...);
132
2
    }
_ZN5doris10DebugPoint16execute_callbackIJPiEEEvDpT_
Line
Count
Source
125
1
    void execute_callback(ARGS... args) {
126
1
        if (!callback.has_value()) {
127
0
            throw std::invalid_argument("No set callback");
128
0
        }
129
130
1
        auto func = std::any_cast<std::function<void(ARGS...)>>(callback);
131
1
        func(args...);
132
1
    }
_ZN5doris10DebugPoint16execute_callbackIJiEEEvDpT_
Line
Count
Source
125
1
    void execute_callback(ARGS... args) {
126
1
        if (!callback.has_value()) {
127
0
            throw std::invalid_argument("No set callback");
128
0
        }
129
130
1
        auto func = std::any_cast<std::function<void(ARGS...)>>(callback);
131
1
        func(args...);
132
1
    }
133
};
134
135
class DebugPoints {
136
public:
137
    bool is_enable(const std::string& name);
138
    std::shared_ptr<DebugPoint> get_debug_point(const std::string& name);
139
    void remove(const std::string& name);
140
    void clear();
141
142
    // if not enable debug point or its params not contains `key`, then return `default_value`
143
    // url: /api/debug_point/add/name?k1=v1&k2=v2&...
144
    template <typename T>
145
    T get_debug_param_or_default(const std::string& name, const std::string& key,
146
6
                                 const T& default_value) {
147
6
        auto debug_point = get_debug_point(name);
148
6
        return debug_point ? debug_point->param(key, default_value) : default_value;
149
6
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultIdEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESA_RKS2_
Line
Count
Source
146
1
                                 const T& default_value) {
147
1
        auto debug_point = get_debug_point(name);
148
1
        return debug_point ? debug_point->param(key, default_value) : default_value;
149
1
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultIiEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESA_RKS2_
Line
Count
Source
146
4
                                 const T& default_value) {
147
4
        auto debug_point = get_debug_point(name);
148
4
        return debug_point ? debug_point->param(key, default_value) : default_value;
149
4
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEET_RKS7_SA_RKS8_
Line
Count
Source
146
1
                                 const T& default_value) {
147
1
        auto debug_point = get_debug_point(name);
148
1
        return debug_point ? debug_point->param(key, default_value) : default_value;
149
1
    }
150
151
    // url: /api/debug_point/add/name?value=v
152
    template <typename T>
153
3
    T get_debug_param_or_default(const std::string& name, const T& default_value) {
154
3
        return get_debug_param_or_default(name, "value", default_value);
155
3
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultIiEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS2_
Line
Count
Source
153
2
    T get_debug_param_or_default(const std::string& name, const T& default_value) {
154
2
        return get_debug_param_or_default(name, "value", default_value);
155
2
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEET_RKS7_RKS8_
Line
Count
Source
153
1
    T get_debug_param_or_default(const std::string& name, const T& default_value) {
154
1
        return get_debug_param_or_default(name, "value", default_value);
155
1
    }
156
157
    void add(const std::string& name, std::shared_ptr<DebugPoint> debug_point);
158
159
    // more 'add' functions for convenient use
160
1
    void add(const std::string& name) { add(name, std::make_shared<DebugPoint>()); }
161
    void add_with_params(const std::string& name,
162
3
                         const std::map<std::string, std::string>& params) {
163
3
        auto debug_point = std::make_shared<DebugPoint>();
164
3
        debug_point->params = params;
165
3
        add(name, debug_point);
166
3
    }
167
    template <typename T>
168
2
    void add_with_value(const std::string& name, const T& value) {
169
2
        add_with_params(name, {{"value", fmt::format("{}", value)}});
170
2
    }
_ZN5doris11DebugPoints14add_with_valueIiEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
168
1
    void add_with_value(const std::string& name, const T& value) {
169
1
        add_with_params(name, {{"value", fmt::format("{}", value)}});
170
1
    }
_ZN5doris11DebugPoints14add_with_valueIA6_cEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
168
1
    void add_with_value(const std::string& name, const T& value) {
169
1
        add_with_params(name, {{"value", fmt::format("{}", value)}});
170
1
    }
171
172
    template <typename... ARGS>
173
2
    void add_with_callback(const std::string& name, std::function<void(ARGS...)> callback) {
174
2
        auto debug_point = std::make_shared<DebugPoint>();
175
2
        debug_point->callback = callback;
176
2
        add(name, debug_point);
177
2
    }
_ZN5doris11DebugPoints17add_with_callbackIJPiEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt8functionIFvDpT_EE
Line
Count
Source
173
1
    void add_with_callback(const std::string& name, std::function<void(ARGS...)> callback) {
174
1
        auto debug_point = std::make_shared<DebugPoint>();
175
1
        debug_point->callback = callback;
176
1
        add(name, debug_point);
177
1
    }
_ZN5doris11DebugPoints17add_with_callbackIJiEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt8functionIFvDpT_EE
Line
Count
Source
173
1
    void add_with_callback(const std::string& name, std::function<void(ARGS...)> callback) {
174
1
        auto debug_point = std::make_shared<DebugPoint>();
175
1
        debug_point->callback = callback;
176
1
        add(name, debug_point);
177
1
    }
178
179
    static DebugPoints* instance();
180
181
private:
182
    DebugPoints();
183
184
    using DebugPointMap = std::map<std::string, std::shared_ptr<DebugPoint>>;
185
186
    // handler(new_debug_points)
187
    void update(std::function<void(DebugPointMap&)>&& handler);
188
189
private:
190
    /// TODO: replace atomic_load/store() on shared_ptr (which is deprecated as of C++20) by C++20 std::atomic<std::shared_ptr>.
191
    /// Clang 15 currently does not support it.
192
    std::shared_ptr<const DebugPointMap> _debug_points;
193
};
194
195
} // namespace doris