From 41670570b6be142d430ac9ae1c1507fba75c94e7 Mon Sep 17 00:00:00 2001 From: Andy Lin <32576375+linlinhaohao888@users.noreply.github.com> Date: Tue, 15 Oct 2019 18:07:44 +0800 Subject: [PATCH] feat(http): support CPU profiling using gperf (#290) --- src/dist/http/pprof_http_service.cpp | 55 ++++++++++++++++++++++++++++ src/dist/http/pprof_http_service.h | 9 +++++ 2 files changed, 64 insertions(+) diff --git a/src/dist/http/pprof_http_service.cpp b/src/dist/http/pprof_http_service.cpp index 6dc1b530f2..e062675244 100644 --- a/src/dist/http/pprof_http_service.cpp +++ b/src/dist/http/pprof_http_service.cpp @@ -20,6 +20,8 @@ #include #include +#include +#include #include "pprof_http_service.h" @@ -408,6 +410,59 @@ void pprof_http_service::growth_handler(const http_request &req, http_response & malloc_ext->GetHeapGrowthStacks(&resp.body); } +// // +// == ip:port/pprof/profile == // +// // +static bool get_cpu_profile(std::string &result, useconds_t seconds) +{ + const char *file_name = "cpu.prof"; + + ProfilerStart(file_name); + usleep(seconds); + ProfilerStop(); + + std::ifstream in(file_name); + if (!in.is_open()) { + result = "No profile file"; + return false; + } + std::ostringstream content; + content << in.rdbuf(); + result = content.str(); + in.close(); + if (remove(file_name) != 0) { + result = "Failed to remove temporary profile file"; + return false; + } + return true; +} + +void pprof_http_service::profile_handler(const http_request &req, http_response &resp) +{ + useconds_t seconds = 60000000; + + const char *req_url = req.full_url.to_string().data(); + size_t len = req.full_url.length(); + string_splitter url_sp(req_url, req_url + len, '?'); + if (url_sp != NULL && ++url_sp != NULL) { + string_splitter param_sp(url_sp.field(), url_sp.field() + url_sp.length(), '&'); + while (param_sp != NULL) { + string_splitter kv_sp(param_sp.field(), param_sp.field() + param_sp.length(), '='); + std::string key(kv_sp.field(), kv_sp.length()); + if (kv_sp != NULL && key == "seconds" && ++kv_sp != NULL) { + char *end_ptr; + seconds = strtoul(kv_sp.field(), &end_ptr, 10) * 1000000; + break; + } + param_sp++; + } + } + + resp.status_code = http_status_code::ok; + + get_cpu_profile(resp.body, seconds); +} + } // namespace dsn #endif // DSN_ENABLE_GPERF diff --git a/src/dist/http/pprof_http_service.h b/src/dist/http/pprof_http_service.h index 051aa65985..0704c9ac1a 100644 --- a/src/dist/http/pprof_http_service.h +++ b/src/dist/http/pprof_http_service.h @@ -42,6 +42,13 @@ class pprof_http_service : public http_service this, std::placeholders::_1, std::placeholders::_2)); + + // ip:port/pprof/profile + register_handler("profile", + std::bind(&pprof_http_service::profile_handler, + this, + std::placeholders::_1, + std::placeholders::_2)); } std::string path() const override { return "pprof"; } @@ -53,6 +60,8 @@ class pprof_http_service : public http_service void cmdline_handler(const http_request &req, http_response &resp); void growth_handler(const http_request &req, http_response &resp); + + void profile_handler(const http_request &req, http_response &resp); }; } // namespace dsn