Coverage Report

Created: 2025-09-05 19:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/doris/be/src/util/debug_points.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
#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
10.7M
    if (UNLIKELY(config::enable_debug_points)) {                              \
38
182k
        auto dp = DebugPoints::instance()->get_debug_point(debug_point_name); \
39
182k
        if (dp) {                                                             \
40
57
            [[maybe_unused]] auto DP_NAME = debug_point_name;                 \
41
57
            code;                                                             \
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty4initEv
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty10add_valuesENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPKvm
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty16add_array_valuesEmPKNS_15CollectionValueEm
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty16add_array_valuesEmPKvPKhS6_m
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty9add_nullsEj
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty15add_array_nullsEPKhm
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty6finishEv
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvENK30InvertedIndexColumnWriterEmpty4sizeEv
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty14close_on_errorEv
42
0
        }                                                                     \
43
182k
    }
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
    do {                                   \
60
        dp->execute_callback(__VA_ARGS__); \
61
    } while (0)
62
63
// example of debug point with callback.
64
//
65
// void demo_callback() {
66
//     int a = 0;
67
//
68
//     DBUG_EXECUTE_IF("set_a", DBUG_RUN_CALLBACK(&a));
69
//     DBUG_EXECUTE_IF("get_a", DBUG_RUN_CALLBACK(a));
70
// }
71
//
72
// TEST(DebugPointsTest, Callback) {
73
//     config::enable_debug_points = true;
74
//     DebugPoints::instance()->clear();
75
//
76
//     int got_a = 0;
77
//
78
//     std::function<void(int*)> set_handler = [](int* a) { *a = 1000; };
79
//     std::function<void(int)> get_handler = [&got_a](int a) { got_a = a; };
80
//     DebugPoints::instance()->add_with_callback("set_a", set_handler);
81
//     DebugPoints::instance()->add_with_callback("get_a", get_handler);
82
//
83
//     demo_callback();
84
//
85
//     EXPECT_EQ(1000, got_a);
86
// }
87
88
namespace doris {
89
90
struct DebugPoint {
91
    std::atomic<int64_t> execute_num {0};
92
    int64_t execute_limit = -1;
93
    int64_t expire_ms = -1;
94
95
    std::map<std::string, std::string> params;
96
97
    // Usually `callback` use in be ut, to exchange local variable between callback code and injected code,
98
    // or change with different injected handlers.
99
    // test/util/debug_points_test.cpp#Callback give a example.
100
    std::any callback;
101
102
    template <typename T>
103
17
    T param(const std::string& key, T default_value = T()) {
104
17
        auto it = params.find(key);
105
17
        if (it == params.end()) {
106
4
            return default_value;
107
4
        }
108
13
        if constexpr (std::is_same_v<T, bool>) {
109
2
            if (it->second == "true") {
110
1
                return true;
111
1
            }
112
1
            if (it->second == "false") {
113
1
                return false;
114
1
            }
115
0
            return boost::lexical_cast<T>(it->second);
116
7
        } else if constexpr (std::is_arithmetic_v<T>) {
117
7
            return boost::lexical_cast<T>(it->second);
118
7
        } else if constexpr (std::is_same_v<T, const char*>) {
119
1
            return it->second.c_str();
120
3
        } else {
121
3
            static_assert(std::is_same_v<T, std::string>);
122
3
            return it->second;
123
3
        }
124
13
    }
_ZN5doris10DebugPoint5paramIiEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
103
5
    T param(const std::string& key, T default_value = T()) {
104
5
        auto it = params.find(key);
105
5
        if (it == params.end()) {
106
1
            return default_value;
107
1
        }
108
        if constexpr (std::is_same_v<T, bool>) {
109
            if (it->second == "true") {
110
                return true;
111
            }
112
            if (it->second == "false") {
113
                return false;
114
            }
115
            return boost::lexical_cast<T>(it->second);
116
4
        } else if constexpr (std::is_arithmetic_v<T>) {
117
4
            return boost::lexical_cast<T>(it->second);
118
        } else if constexpr (std::is_same_v<T, const char*>) {
119
            return it->second.c_str();
120
        } else {
121
            static_assert(std::is_same_v<T, std::string>);
122
            return it->second;
123
        }
124
4
    }
_ZN5doris10DebugPoint5paramINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEET_RKS7_S8_
Line
Count
Source
103
3
    T param(const std::string& key, T default_value = T()) {
104
3
        auto it = params.find(key);
105
3
        if (it == params.end()) {
106
0
            return default_value;
107
0
        }
108
        if constexpr (std::is_same_v<T, bool>) {
109
            if (it->second == "true") {
110
                return true;
111
            }
112
            if (it->second == "false") {
113
                return false;
114
            }
115
            return boost::lexical_cast<T>(it->second);
116
        } else if constexpr (std::is_arithmetic_v<T>) {
117
            return boost::lexical_cast<T>(it->second);
118
        } else if constexpr (std::is_same_v<T, const char*>) {
119
            return it->second.c_str();
120
3
        } else {
121
3
            static_assert(std::is_same_v<T, std::string>);
122
3
            return it->second;
123
3
        }
124
3
    }
_ZN5doris10DebugPoint5paramIPKcEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES4_
Line
Count
Source
103
2
    T param(const std::string& key, T default_value = T()) {
104
2
        auto it = params.find(key);
105
2
        if (it == params.end()) {
106
1
            return default_value;
107
1
        }
108
        if constexpr (std::is_same_v<T, bool>) {
109
            if (it->second == "true") {
110
                return true;
111
            }
112
            if (it->second == "false") {
113
                return false;
114
            }
115
            return boost::lexical_cast<T>(it->second);
116
        } else if constexpr (std::is_arithmetic_v<T>) {
117
            return boost::lexical_cast<T>(it->second);
118
1
        } else if constexpr (std::is_same_v<T, const char*>) {
119
1
            return it->second.c_str();
120
        } else {
121
            static_assert(std::is_same_v<T, std::string>);
122
            return it->second;
123
        }
124
1
    }
_ZN5doris10DebugPoint5paramIdEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
103
3
    T param(const std::string& key, T default_value = T()) {
104
3
        auto it = params.find(key);
105
3
        if (it == params.end()) {
106
0
            return default_value;
107
0
        }
108
        if constexpr (std::is_same_v<T, bool>) {
109
            if (it->second == "true") {
110
                return true;
111
            }
112
            if (it->second == "false") {
113
                return false;
114
            }
115
            return boost::lexical_cast<T>(it->second);
116
3
        } else if constexpr (std::is_arithmetic_v<T>) {
117
3
            return boost::lexical_cast<T>(it->second);
118
        } else if constexpr (std::is_same_v<T, const char*>) {
119
            return it->second.c_str();
120
        } else {
121
            static_assert(std::is_same_v<T, std::string>);
122
            return it->second;
123
        }
124
3
    }
_ZN5doris10DebugPoint5paramIbEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
103
2
    T param(const std::string& key, T default_value = T()) {
104
2
        auto it = params.find(key);
105
2
        if (it == params.end()) {
106
0
            return default_value;
107
0
        }
108
2
        if constexpr (std::is_same_v<T, bool>) {
109
2
            if (it->second == "true") {
110
1
                return true;
111
1
            }
112
1
            if (it->second == "false") {
113
1
                return false;
114
1
            }
115
0
            return boost::lexical_cast<T>(it->second);
116
        } else if constexpr (std::is_arithmetic_v<T>) {
117
            return boost::lexical_cast<T>(it->second);
118
        } else if constexpr (std::is_same_v<T, const char*>) {
119
            return it->second.c_str();
120
        } else {
121
            static_assert(std::is_same_v<T, std::string>);
122
            return it->second;
123
        }
124
2
    }
_ZN5doris10DebugPoint5paramIlEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
103
2
    T param(const std::string& key, T default_value = T()) {
104
2
        auto it = params.find(key);
105
2
        if (it == params.end()) {
106
2
            return default_value;
107
2
        }
108
        if constexpr (std::is_same_v<T, bool>) {
109
            if (it->second == "true") {
110
                return true;
111
            }
112
            if (it->second == "false") {
113
                return false;
114
            }
115
            return boost::lexical_cast<T>(it->second);
116
0
        } else if constexpr (std::is_arithmetic_v<T>) {
117
0
            return boost::lexical_cast<T>(it->second);
118
        } else if constexpr (std::is_same_v<T, const char*>) {
119
            return it->second.c_str();
120
        } else {
121
            static_assert(std::is_same_v<T, std::string>);
122
            return it->second;
123
        }
124
0
    }
125
126
    template <typename... ARGS>
127
2
    void execute_callback(ARGS... args) {
128
2
        if (!callback.has_value()) {
129
0
            throw std::invalid_argument("No set callback");
130
0
        }
131
132
2
        auto func = std::any_cast<std::function<void(ARGS...)>>(callback);
133
2
        func(args...);
134
2
    }
_ZN5doris10DebugPoint16execute_callbackIJPiEEEvDpT_
Line
Count
Source
127
1
    void execute_callback(ARGS... args) {
128
1
        if (!callback.has_value()) {
129
0
            throw std::invalid_argument("No set callback");
130
0
        }
131
132
1
        auto func = std::any_cast<std::function<void(ARGS...)>>(callback);
133
1
        func(args...);
134
1
    }
_ZN5doris10DebugPoint16execute_callbackIJiEEEvDpT_
Line
Count
Source
127
1
    void execute_callback(ARGS... args) {
128
1
        if (!callback.has_value()) {
129
0
            throw std::invalid_argument("No set callback");
130
0
        }
131
132
1
        auto func = std::any_cast<std::function<void(ARGS...)>>(callback);
133
1
        func(args...);
134
1
    }
135
};
136
137
class DebugPoints {
138
public:
139
    bool is_enable(const std::string& name);
140
    std::shared_ptr<DebugPoint> get_debug_point(const std::string& name);
141
    void remove(const std::string& name);
142
    void clear();
143
144
    // if not enable debug point or its params not contains `key`, then return `default_value`
145
    // url: /api/debug_point/add/name?k1=v1&k2=v2&...
146
    template <typename T>
147
    T get_debug_param_or_default(const std::string& name, const std::string& key,
148
6
                                 const T& default_value) {
149
6
        auto debug_point = get_debug_point(name);
150
6
        return debug_point ? debug_point->param(key, default_value) : default_value;
151
6
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultIdEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESA_RKS2_
Line
Count
Source
148
1
                                 const T& default_value) {
149
1
        auto debug_point = get_debug_point(name);
150
1
        return debug_point ? debug_point->param(key, default_value) : default_value;
151
1
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultIiEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESA_RKS2_
Line
Count
Source
148
4
                                 const T& default_value) {
149
4
        auto debug_point = get_debug_point(name);
150
4
        return debug_point ? debug_point->param(key, default_value) : default_value;
151
4
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEET_RKS7_SA_RKS8_
Line
Count
Source
148
1
                                 const T& default_value) {
149
1
        auto debug_point = get_debug_point(name);
150
1
        return debug_point ? debug_point->param(key, default_value) : default_value;
151
1
    }
Unexecuted instantiation: _ZN5doris11DebugPoints26get_debug_param_or_defaultIlEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESA_RKS2_
152
153
    // url: /api/debug_point/add/name?value=v
154
    template <typename T>
155
3
    T get_debug_param_or_default(const std::string& name, const T& default_value) {
156
3
        return get_debug_param_or_default(name, "value", default_value);
157
3
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultIiEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS2_
Line
Count
Source
155
2
    T get_debug_param_or_default(const std::string& name, const T& default_value) {
156
2
        return get_debug_param_or_default(name, "value", default_value);
157
2
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEET_RKS7_RKS8_
Line
Count
Source
155
1
    T get_debug_param_or_default(const std::string& name, const T& default_value) {
156
1
        return get_debug_param_or_default(name, "value", default_value);
157
1
    }
158
159
    void add(const std::string& name, std::shared_ptr<DebugPoint> debug_point);
160
161
    // more 'add' functions for convenient use
162
48
    void add(const std::string& name) { add(name, std::make_shared<DebugPoint>()); }
163
    void add_with_params(const std::string& name,
164
3
                         const std::map<std::string, std::string>& params) {
165
3
        auto debug_point = std::make_shared<DebugPoint>();
166
3
        debug_point->params = params;
167
3
        add(name, debug_point);
168
3
    }
169
    template <typename T>
170
2
    void add_with_value(const std::string& name, const T& value) {
171
2
        add_with_params(name, {{"value", fmt::format("{}", value)}});
172
2
    }
_ZN5doris11DebugPoints14add_with_valueIiEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
170
1
    void add_with_value(const std::string& name, const T& value) {
171
1
        add_with_params(name, {{"value", fmt::format("{}", value)}});
172
1
    }
_ZN5doris11DebugPoints14add_with_valueIA6_cEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
170
1
    void add_with_value(const std::string& name, const T& value) {
171
1
        add_with_params(name, {{"value", fmt::format("{}", value)}});
172
1
    }
173
174
    template <typename... ARGS>
175
2
    void add_with_callback(const std::string& name, std::function<void(ARGS...)> callback) {
176
2
        auto debug_point = std::make_shared<DebugPoint>();
177
2
        debug_point->callback = callback;
178
2
        add(name, debug_point);
179
2
    }
_ZN5doris11DebugPoints17add_with_callbackIJPiEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt8functionIFvDpT_EE
Line
Count
Source
175
1
    void add_with_callback(const std::string& name, std::function<void(ARGS...)> callback) {
176
1
        auto debug_point = std::make_shared<DebugPoint>();
177
1
        debug_point->callback = callback;
178
1
        add(name, debug_point);
179
1
    }
_ZN5doris11DebugPoints17add_with_callbackIJiEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt8functionIFvDpT_EE
Line
Count
Source
175
1
    void add_with_callback(const std::string& name, std::function<void(ARGS...)> callback) {
176
1
        auto debug_point = std::make_shared<DebugPoint>();
177
1
        debug_point->callback = callback;
178
1
        add(name, debug_point);
179
1
    }
180
181
    static DebugPoints* instance();
182
183
private:
184
    DebugPoints();
185
186
    using DebugPointMap = std::map<std::string, std::shared_ptr<DebugPoint>>;
187
188
    // handler(new_debug_points)
189
    void update(std::function<void(DebugPointMap&)>&& handler);
190
191
private:
192
    std::atomic<std::shared_ptr<const DebugPointMap>> _debug_points;
193
};
194
195
} // namespace doris