Coverage Report

Created: 2026-03-13 09:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/service/http/action/jeprofile_actions.cpp
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
#include "service/http/action/jeprofile_actions.h"
19
20
#include <jemalloc/jemalloc.h>
21
#include <unistd.h>
22
23
#include <string>
24
25
#include "agent/utils.h"
26
#include "runtime/memory/heap_profiler.h"
27
#include "service/http/ev_http_server.h"
28
#include "service/http/http_channel.h"
29
#include "service/http/http_handler.h"
30
#include "service/http/http_handler_with_auth.h"
31
#include "service/http/http_headers.h"
32
#include "service/http/http_request.h"
33
34
namespace doris {
35
36
const static std::string HEADER_JSON = "application/json";
37
const static std::string START_HEAP_PROFILE_NOTICE =
38
        "`curl http://be_host:be_webport/jeheap/active/true` to start heap profiler, note that "
39
        "`JEMALLOC_CONF` in `be/conf/be.conf` must contain `prof:true`, will only track and sample "
40
        "the memory "
41
        "allocated and freed after the heap profiler started, it cannot analyze the "
42
        "memory allocated and freed before. Therefore, dumping the heap profile "
43
        "immediately after start heap profiler may prompt `No nodes to print`, try rerun your "
44
        "query and dump the heap profile. Sometimes restarting BE and then immediately executing "
45
        "`curl http://be_host:be_webport/jeheap/active/true` makes it easier to analyze the "
46
        "problem.\n"
47
        "If you want to analyze the memory during the BE process startup, need to modify be.conf "
48
        "and restart the BE process, open `be/conf/be.conf` and add `,prof_active:true` after "
49
        "`JEMALLOC_CONF`, or modify `prof_active:false` to `prof:true`.\n";
50
51
0
static bool compile_check(HttpRequest* req) {
52
0
#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || defined(THREAD_SANITIZER)
53
0
    HttpChannel::send_reply(
54
0
            req, HttpStatus::INTERNAL_SERVER_ERROR,
55
0
            "Jemalloc heap dump is not available with ASAN(address sanitizer) builds.\n");
56
0
    return false;
57
#elif !defined(USE_JEMALLOC)
58
    HttpChannel::send_reply(req, HttpStatus::INTERNAL_SERVER_ERROR,
59
                            "jemalloc heap dump is not available without setting USE_JEMALLOC.\n");
60
    return false;
61
#else
62
    return true;
63
#endif
64
0
}
65
66
0
static bool conf_check(HttpRequest* req) {
67
0
    if (!HeapProfiler::instance()->check_active_heap_profiler()) {
68
0
        HttpChannel::send_reply(req, HttpStatus::INTERNAL_SERVER_ERROR,
69
0
                                "Jemalloc heap profiler is not enabled, refer to the following "
70
0
                                "method to enable it.\n" +
71
0
                                        START_HEAP_PROFILE_NOTICE);
72
0
        return false;
73
0
    }
74
0
    return true;
75
0
}
76
77
0
void SetJeHeapProfileActiveActions::handle(HttpRequest* req) {
78
0
    req->add_output_header(HttpHeaders::CONTENT_TYPE, HEADER_JSON.c_str());
79
0
    if (compile_check(req)) {
80
0
        if (req->param("prof_value") == "true") {
81
0
            HeapProfiler::instance()->heap_profiler_start();
82
0
            HttpChannel::send_reply(req, HttpStatus::OK,
83
0
                                    "Jemalloc heap profiler started\n" + START_HEAP_PROFILE_NOTICE);
84
0
        } else {
85
0
            HeapProfiler::instance()->heap_profiler_stop();
86
0
            HttpChannel::send_reply(req, HttpStatus::OK, "heap profiler stoped\n");
87
0
        }
88
0
    }
89
0
}
90
91
0
void SetJeHeapProfileResetActions::handle(HttpRequest* req) {
92
0
    req->add_output_header(HttpHeaders::CONTENT_TYPE, HEADER_JSON.c_str());
93
0
    if (compile_check(req)) {
94
0
        const auto& lg_sample_str = req->param("reset_value");
95
0
        size_t lg_sample = std::stol(lg_sample_str);
96
0
        if (lg_sample > 0 && HeapProfiler::instance()->check_enable_heap_profiler() &&
97
0
            HeapProfiler::instance()->heap_profiler_reset(lg_sample)) {
98
0
            HttpChannel::send_reply(req, HttpStatus::OK,
99
0
                                    fmt::format("Jemalloc reset all memory profile statistics and "
100
0
                                                "update the sample rate:{}\n",
101
0
                                                lg_sample_str));
102
0
        } else {
103
0
            HttpChannel::send_reply(req, HttpStatus::OK,
104
0
                                    "Jemalloc have not reset.\nThe `JEMALLOC_CONF` in "
105
0
                                    "`be/conf/be.conf` must contain `prof:true`.\n");
106
0
        }
107
0
    }
108
0
}
109
110
0
void DumpJeHeapProfileToDotActions::handle(HttpRequest* req) {
111
0
    req->add_output_header(HttpHeaders::CONTENT_TYPE, HEADER_JSON.c_str());
112
0
    if (compile_check(req) && conf_check(req)) {
113
0
        std::string dot = HeapProfiler::instance()->dump_heap_profile_to_dot();
114
0
        if (dot.empty()) {
115
0
            HttpChannel::send_reply(req, HttpStatus::INTERNAL_SERVER_ERROR,
116
0
                                    "dump heap profile to dot failed, see be.INFO\n");
117
0
        } else {
118
0
            std::string msg;
119
0
            AgentUtils util;
120
0
            dot += "\n-------------------------------------------------------\n";
121
0
            util.exec_cmd("type addr2line", &msg);
122
0
            dot += "addr2line: " + msg + "\n";
123
0
            dot += "Copy the text after `digraph` in the above output to "
124
0
                   "http://www.webgraphviz.com to generate a dot graph.\n"
125
0
                   "after start heap profiler, if there is no operation, will print `No nodes to "
126
0
                   "print`."
127
0
                   "If there are many errors: `addr2line: Dwarf Error`,"
128
0
                   "or other FAQ, reference doc: "
129
0
                   "https://doris.apache.org/community/developer-guide/debug-tool/#4-qa\n";
130
0
            HttpChannel::send_reply(req, HttpStatus::OK, dot);
131
0
        }
132
0
    }
133
0
}
134
135
0
void DumpJeHeapProfileActions::handle(HttpRequest* req) {
136
0
    req->add_output_header(HttpHeaders::CONTENT_TYPE, HEADER_JSON.c_str());
137
0
    if (compile_check(req) && conf_check(req)) {
138
0
        std::string profile_file_name = HeapProfiler::instance()->dump_heap_profile();
139
0
        if (profile_file_name.empty()) {
140
0
            HttpChannel::send_reply(req, HttpStatus::INTERNAL_SERVER_ERROR,
141
0
                                    "jemalloc heap dump failed\n");
142
0
        } else {
143
0
            HttpChannel::send_reply(req, HttpStatus::OK,
144
0
                                    fmt::format("jemalloc heap dump success, dump file path: {}\n",
145
0
                                                profile_file_name));
146
0
        }
147
0
    }
148
0
}
149
150
} // namespace doris