-
Notifications
You must be signed in to change notification settings - Fork 59
feat: update the way to get heap profile #433
Changes from 15 commits
94a8072
2f246cc
0b885b5
9eaa36f
3a4e8f0
02b09b9
1c67745
8540039
9401a77
dcbd450
03c6a0c
347be03
0440c90
f982880
7ffc9af
d479f26
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -25,10 +25,12 @@ | |||||||||
|
||||||||||
#include "pprof_http_service.h" | ||||||||||
|
||||||||||
#include <dsn/dist/fmt_logging.h> | ||||||||||
#include <dsn/utility/string_conv.h> | ||||||||||
#include <dsn/utility/defer.h> | ||||||||||
#include <dsn/utility/timer.h> | ||||||||||
#include <dsn/utility/string_splitter.h> | ||||||||||
#include <gperftools/heap-profiler.h> | ||||||||||
#include <gperftools/malloc_extension.h> | ||||||||||
#include <gperftools/profiler.h> | ||||||||||
|
||||||||||
|
@@ -319,26 +321,39 @@ void pprof_http_service::symbol_handler(const http_request &req, http_response & | |||||||||
// // | ||||||||||
// == ip:port/pprof/heap == // | ||||||||||
// // | ||||||||||
void pprof_http_service::heap_handler(const http_request &req, http_response &resp) | ||||||||||
{ | ||||||||||
bool in_pprof = false; | ||||||||||
if (!_in_pprof_action.compare_exchange_strong(in_pprof, true)) { | ||||||||||
dwarn_f("node is already exectuting pprof action, please wait and retry"); | ||||||||||
resp.status_code = http_status_code::internal_server_error; | ||||||||||
return; | ||||||||||
} | ||||||||||
|
||||||||||
static constexpr const char *TCMALLOC_SAMPLE_PARAMETER = "TCMALLOC_SAMPLE_PARAMETER"; | ||||||||||
|
||||||||||
static bool is_heap_profile_enabled() { return ::getenv(TCMALLOC_SAMPLE_PARAMETER) != nullptr; } | ||||||||||
const std::string SECOND = "seconds"; | ||||||||||
neverchanje marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
const uint32_t kDefaultSecond = 10; | ||||||||||
|
||||||||||
static bool get_heap_profile(std::string &result) | ||||||||||
{ | ||||||||||
if (!is_heap_profile_enabled()) { | ||||||||||
result = "no TCMALLOC_SAMPLE_PARAMETER in env"; | ||||||||||
return false; | ||||||||||
// get seconds from query params, default value is `kDefaultSecond` | ||||||||||
uint32_t seconds = kDefaultSecond; | ||||||||||
const auto iter = req.query_args.find(SECOND); | ||||||||||
if (iter != req.query_args.end()) { | ||||||||||
const auto seconds_str = iter->second; | ||||||||||
dsn::internal::buf2unsigned(seconds_str, seconds); | ||||||||||
} | ||||||||||
MallocExtension::instance()->GetHeapSample(&result); | ||||||||||
return true; | ||||||||||
} | ||||||||||
|
||||||||||
void pprof_http_service::heap_handler(const http_request &req, http_response &resp) | ||||||||||
{ | ||||||||||
std::stringstream profile_name_prefix; | ||||||||||
profile_name_prefix << "heap_profile." << getpid() << "." << dsn_now_ns(); | ||||||||||
|
||||||||||
HeapProfilerStart(profile_name_prefix.str().c_str()); | ||||||||||
sleep(seconds); | ||||||||||
const char *profile = GetHeapProfile(); | ||||||||||
HeapProfilerStop(); | ||||||||||
|
||||||||||
resp.status_code = http_status_code::ok; | ||||||||||
resp.body = profile; | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Has the problem that response too large and http server can not deal with been solved? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have read source code, and find that GetHeapProfile will return buffers at most 1MB.
During my test, I have observed that some middle profile files whose size will not exceed 1M, it proves the file size limit. |
||||||||||
delete profile; | ||||||||||
|
||||||||||
get_heap_profile(resp.body); | ||||||||||
_in_pprof_action.store(false); | ||||||||||
} | ||||||||||
|
||||||||||
// // | ||||||||||
|
@@ -405,9 +420,18 @@ void pprof_http_service::cmdline_handler(const http_request &req, http_response | |||||||||
|
||||||||||
void pprof_http_service::growth_handler(const http_request &req, http_response &resp) | ||||||||||
{ | ||||||||||
bool in_pprof = false; | ||||||||||
if (!_in_pprof_action.compare_exchange_strong(in_pprof, true)) { | ||||||||||
dwarn_f("node is already exectuting pprof action, please wait and retry"); | ||||||||||
resp.status_code = http_status_code::internal_server_error; | ||||||||||
Comment on lines
+425
to
+426
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
return; | ||||||||||
} | ||||||||||
|
||||||||||
MallocExtension *malloc_ext = MallocExtension::instance(); | ||||||||||
ddebug("received requests for growth profile"); | ||||||||||
malloc_ext->GetHeapGrowthStacks(&resp.body); | ||||||||||
|
||||||||||
_in_pprof_action.store(false); | ||||||||||
} | ||||||||||
|
||||||||||
// // | ||||||||||
|
@@ -439,6 +463,13 @@ static bool get_cpu_profile(std::string &result, useconds_t seconds) | |||||||||
|
||||||||||
void pprof_http_service::profile_handler(const http_request &req, http_response &resp) | ||||||||||
{ | ||||||||||
bool in_pprof = false; | ||||||||||
if (!_in_pprof_action.compare_exchange_strong(in_pprof, true)) { | ||||||||||
dwarn_f("node is already exectuting pprof action, please wait and retry"); | ||||||||||
resp.status_code = http_status_code::internal_server_error; | ||||||||||
Comment on lines
+468
to
+469
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I consider that Filling error msg into response body is to tell client the reason why this request failed. However, I tried to this, and found out the pprof only print http status_code while meet error, like below:
I think we should print error log in server side, http status code is enough for client. |
||||||||||
return; | ||||||||||
} | ||||||||||
|
||||||||||
useconds_t seconds = 60000000; | ||||||||||
|
||||||||||
const char *req_url = req.full_url.to_string().data(); | ||||||||||
|
@@ -461,6 +492,8 @@ void pprof_http_service::profile_handler(const http_request &req, http_response | |||||||||
resp.status_code = http_status_code::ok; | ||||||||||
|
||||||||||
get_cpu_profile(resp.body, seconds); | ||||||||||
|
||||||||||
_in_pprof_action.store(false); | ||||||||||
} | ||||||||||
|
||||||||||
} // namespace dsn | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.