Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
pprof-path-handlers.cc
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
17 #include <boost/bind.hpp>
18 #include <fstream>
19 #include <sys/stat.h>
20 #include <google/profiler.h>
21 #include <google/heap-profiler.h>
22 #include <google/malloc_extension.h>
23 
24 #include "common/logging.h"
25 #include "util/webserver.h"
26 
27 #include "common/names.h"
28 
29 using namespace google;
30 using namespace impala;
31 using namespace rapidjson;
32 
33 DECLARE_string(heap_profile_dir);
34 
35 const int PPROF_DEFAULT_SAMPLE_SECS = 30; // pprof default sample time in seconds.
36 
37 typedef boost::function<void
38  (const Webserver::ArgumentMap& args, std::stringstream* output)> PprofCallback;
39 
40 // Wrapper for all Pprof*Handler methods that want to write to a stringstream, this method
41 // adds the output of the string to a Json document in the 'contents' member.
42 void PprofJsonHandler(const PprofCallback& callback, const Webserver::ArgumentMap& args,
43  Document* document) {
44  stringstream ss;
45  callback(args, &ss);
46  Value output(ss.str().c_str(), document->GetAllocator());
47  document->AddMember("contents", output, document->GetAllocator());
48 }
49 
50 // pprof asks for the url /pprof/cmdline to figure out what application it's profiling.
51 // The server should respond by reading the contents of /proc/self/cmdline.
52 void PprofCmdLineHandler(const Webserver::ArgumentMap& args, stringstream* output) {
53  ifstream cmd_line_file("/proc/self/cmdline", ios::in);
54  if (!cmd_line_file.is_open()) {
55  (*output) << "Unable to open file: /proc/self/cmdline";
56  return;
57  } else {
58  (*output) << cmd_line_file.rdbuf();
59  cmd_line_file.close();
60  }
61 }
62 
63 // pprof asks for the url /pprof/heap to get heap information. This should be implemented
64 // by calling HeapProfileStart(filename), continue to do work, and then, some number of
65 // seconds later, call GetHeapProfile() followed by HeapProfilerStop().
66 void PprofHeapHandler(const Webserver::ArgumentMap& args, stringstream* output) {
67 #ifdef ADDRESS_SANITIZER
68  (*output) << "Heap profiling is not available with address sanitizer builds.";
69 #else
70  Webserver::ArgumentMap::const_iterator it = args.find("seconds");
71  int seconds = PPROF_DEFAULT_SAMPLE_SECS;
72  if (it != args.end()) {
73  seconds = atoi(it->second.c_str());
74  }
75 
76  HeapProfilerStart(FLAGS_heap_profile_dir.c_str());
77  // Sleep to allow for some samples to be collected.
78  sleep(seconds);
79  const char* profile = GetHeapProfile();
80  HeapProfilerStop();
81  (*output) << profile;
82  delete profile;
83 #endif
84 }
85 
86 // pprof asks for the url /pprof/profile?seconds=XX to get cpu-profiling information.
87 // The server should respond by calling ProfilerStart(), continuing to do its work,
88 // and then, XX seconds later, calling ProfilerStop().
89 void PprofCpuProfileHandler(const Webserver::ArgumentMap& args, stringstream* output) {
90 #ifdef ADDRESS_SANITIZER
91  (*output) << "CPU profiling is not available with address sanitizer builds.";
92 #else
93  Webserver::ArgumentMap::const_iterator it = args.find("seconds");
94  int seconds = PPROF_DEFAULT_SAMPLE_SECS;
95  if (it != args.end()) {
96  seconds = atoi(it->second.c_str());
97  }
98  ostringstream tmp_prof_file_name;
99  // Build a temporary file name that is hopefully unique.
100  tmp_prof_file_name << "/tmp/impala_cpu_profile." << getpid() << "." << rand();
101  ProfilerStart(tmp_prof_file_name.str().c_str());
102  sleep(seconds);
103  ProfilerStop();
104  ifstream prof_file(tmp_prof_file_name.str().c_str(), ios::in);
105  if (!prof_file.is_open()) {
106  (*output) << "Unable to open cpu profile: " << tmp_prof_file_name;
107  return;
108  }
109  (*output) << prof_file.rdbuf();
110  prof_file.close();
111 #endif
112 }
113 
114 // pprof asks for the url /pprof/growth to get heap-profiling delta (growth) information.
115 // The server should respond by calling:
116 // MallocExtension::instance()->GetHeapGrowthStacks(&output);
117 void PprofGrowthHandler(const Webserver::ArgumentMap& args, stringstream* output) {
118 #ifdef ADDRESS_SANITIZER
119  (*output) << "Growth profiling is not available with address sanitizer builds.";
120 #else
121  string heap_growth_stack;
122  MallocExtension::instance()->GetHeapGrowthStacks(&heap_growth_stack);
123  (*output) << heap_growth_stack;
124 #endif
125 }
126 
127 // pprof asks for the url /pprof/symbol to map from hex addresses to variable names.
128 // When the server receives a GET request for /pprof/symbol, it should return a line
129 // formatted like: num_symbols: ###
130 // where ### is the number of symbols found in the binary. For now, the only important
131 // distinction is whether the value is 0, which it is for executables that lack debug
132 // information, or not-0).
133 //
134 // TODO: This part is not implemented:
135 // In addition to the GET request for this url, the server must accept POST requests.
136 // This means that after the HTTP headers, pprof will pass in a list of hex addresses
137 // connected by +, like:
138 // curl -d '0x0824d061+0x0824d1cf' http://remote_host:80/pprof/symbol
139 // The server should read the POST data, which will be in one line, and for each hex value
140 // should write one line of output to the output stream, like so:
141 // <hex address><tab><function name>
142 // For instance:
143 // 0x08b2dabd _Update
144 void PprofSymbolHandler(const Webserver::ArgumentMap& args, stringstream* output) {
145  // TODO: Implement symbol resolution. Without this, the binary needs to be passed
146  // to pprof to resolve all symbols.
147  (*output) << "num_symbols: 0";
148 }
149 
151  // Path handlers for remote pprof profiling. For information see:
152  // https://gperftools.googlecode.com/svn/trunk/doc/pprof_remote_servers.html
153  webserver->RegisterUrlCallback("/pprof/cmdline", "raw_text.tmpl",
154  bind<void>(PprofJsonHandler, PprofCmdLineHandler, _1, _2), false);
155  webserver->RegisterUrlCallback("/pprof/heap", "raw_text.tmpl",
156  bind<void>(PprofJsonHandler, PprofHeapHandler, _1, _2), false);
157  webserver->RegisterUrlCallback("/pprof/growth", "raw_text.tmpl",
158  bind<void>(PprofJsonHandler, PprofGrowthHandler, _1, _2), false);
159  webserver->RegisterUrlCallback("/pprof/profile", "raw_text.tmpl",
160  bind<void>(PprofJsonHandler, PprofCpuProfileHandler, _1, _2), false);
161  webserver->RegisterUrlCallback("/pprof/symbol", "raw_text.tmpl",
162  bind<void>(PprofJsonHandler, PprofSymbolHandler, _1, _2), false);
163 }
void PprofCpuProfileHandler(const Webserver::ArgumentMap &args, stringstream *output)
void PprofHeapHandler(const Webserver::ArgumentMap &args, stringstream *output)
void PprofGrowthHandler(const Webserver::ArgumentMap &args, stringstream *output)
boost::function< void(const Webserver::ArgumentMap &args, std::stringstream *output)> PprofCallback
void RegisterUrlCallback(const std::string &path, const std::string &template_filename, const UrlCallback &callback, bool is_on_nav_bar=true)
Only one callback may be registered per URL.
Definition: webserver.cc:412
std::map< std::string, std::string > ArgumentMap
Definition: webserver.h:36
void PprofCmdLineHandler(const Webserver::ArgumentMap &args, stringstream *output)
const int PPROF_DEFAULT_SAMPLE_SECS
void AddPprofUrlCallbacks(Webserver *webserver)
Adds set of path handlers to support pprof profiling of a remote server.
void PprofSymbolHandler(const Webserver::ArgumentMap &args, stringstream *output)
DECLARE_string(heap_profile_dir)
void PprofJsonHandler(const PprofCallback &callback, const Webserver::ArgumentMap &args, Document *document)