4 #include <unordered_map> 6 #include <gperftools/heap-profiler.h> 7 #include <gperftools/malloc_extension.h> 8 #include <gperftools/profiler.h> 10 #include "base/logging.h" 11 #include "base/walltime.h" 12 #include "strings/human_readable.h" 13 #include "strings/numbers.h" 14 #include "strings/split.h" 15 #include "strings/strcat.h" 16 #include "util/fibers/fibers_ext.h" 17 #include "util/http/http_common.h" 18 #include "util/spawn.h" 23 char last_profile_suffix[100] = {0};
27 using namespace boost;
28 using beast::http::field;
29 namespace h2 = beast::http;
30 typedef h2::response<h2::string_body> StringResponse;
32 static void HandleCpuProfile(
bool enable, StringResponse* response) {
33 string profile_name =
"/tmp/" + base::ProgramBaseName();
34 response->set(h2::field::cache_control,
"no-cache, no-store, must-revalidate");
35 response->set(h2::field::pragma,
"no-cache");
36 response->set(field::content_type, kHtmlMime);
38 auto& body = response->body();
41 if (last_profile_suffix[0]) {
42 body.append(
"<p> Yo, already profiling, stupid!</p>\n");
44 string suffix = base::LocalTimeNow(
"_%d%m%Y_%H%M%S.prof");
45 profile_name.append(suffix);
46 strcpy(last_profile_suffix, suffix.c_str());
47 int res = ProfilerStart(profile_name.c_str());
48 LOG(INFO) <<
"Starting profiling into " << profile_name <<
" " << res;
50 "<h1> Wow, your code is so fast!</h1> \n" 52 "src='https://gist.github.com/romange/4760c3eebc407755f856fec8e5b6d4c1/raw/" 53 "8da7e4129da2ebef26a0fad7b637364439f33e97/profiler2.gif'>\n");
58 if (last_profile_suffix[0] ==
'\0') {
59 body.append(
"<h3>Profiling is off, commander!</h3> \n")
60 .append(
"<img src='https://i.giphy.com/media/l0IykG0AM7911MrCM/giphy.webp'>\n");
63 string cmd(
"nice -n 15 pprof -noinlines -lines -unit ms --svg ");
64 string symbols_name = base::ProgramAbsoluteFileName() +
".debug";
65 LOG(INFO) <<
"Symbols " << symbols_name <<
", suffix: " << last_profile_suffix;
66 if (access(symbols_name.c_str(), R_OK) != 0) {
67 symbols_name = base::ProgramAbsoluteFileName();
69 cmd.append(symbols_name).append(
" ");
71 profile_name.append(last_profile_suffix);
72 cmd.append(profile_name).append(
" > ");
74 string err_log = profile_name +
".err";
75 profile_name.append(
".svg");
77 cmd.append(profile_name).append(
" 2> ").append(err_log);
79 LOG(INFO) <<
"Running command: " << cmd;
80 last_profile_suffix[0] =
'\0';
82 int sh_res = util::sh_exec(cmd.c_str());
84 LOG(ERROR) <<
"Error running sh_exec, status: " << errno <<
" " << strerror(errno);
88 string url(
"filez?file=");
89 url.append(profile_name);
90 LOG(INFO) <<
"Redirecting to " << url;
91 google::FlushLogFiles(google::INFO);
93 response->set(h2::field::location, url);
94 response->result(h2::status::moved_permanently);
97 static void HandleHeapProfile(
bool enable, StringResponse* response) {
98 string profile_name =
"/tmp/" + base::ProgramBaseName();
99 response->set(h2::field::cache_control,
"no-cache, no-store, must-revalidate");
100 response->set(h2::field::pragma,
"no-cache");
101 response->set(field::content_type, kHtmlMime);
102 auto& body = response->body();
105 if (IsHeapProfilerRunning()) {
106 body.append(
"<p> Man, heap profiling is already running, relax!</p>\n");
108 string suffix = base::LocalTimeNow(
"_heap_%d%m%Y_%H%M%S");
109 profile_name.append(suffix);
110 HeapProfilerStart(profile_name.c_str());
111 LOG(INFO) <<
"Starting heap profiling into " << profile_name;
112 body.append(
"<p> Let's find memory leaks, w00t!</p> \n");
117 "<h3>Heap profiling is off, master!</h3> \n" 118 "<img src='https://i.giphy.com/media/l0IykG0AM7911MrCM/giphy.webp'>\n");
122 StringResponse ProfilezHandler(
const QueryArgs& args) {
125 for (
const auto& k_v : args) {
126 if (k_v.first ==
"profile") {
127 enable = (k_v.second ==
"on");
128 }
else if (k_v.first ==
"heap") {
130 enable = (k_v.second ==
"on");
134 fibers_ext::Done done;
135 StringResponse response;
136 std::thread([=, &response]()
mutable {
138 HandleCpuProfile(enable, &response);
140 HandleHeapProfile(enable, &response);