1 // Copyright (c) 2005, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 // ---
31 // Author: Sanjay Ghemawat
32 // Chris Demetriou (refactoring)
33 //
34 // Profile current program by sampling stack-trace every so often
35
36 #include "config.h"
37 #include "getpc.h" // should be first to get the _GNU_SOURCE dfn
38 #include <signal.h>
39 #include <assert.h>
40 #include <stdio.h>
41 #include <errno.h>
42 #include <string.h>
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h> // for getpid()
45 #endif
46 #if defined(HAVE_SYS_UCONTEXT_H)
47 #include <sys/ucontext.h>
48 #elif defined(HAVE_UCONTEXT_H)
49 #include <ucontext.h>
50 #elif defined(HAVE_CYGWIN_SIGNAL_H)
51 #include <cygwin/signal.h>
52 typedef ucontext ucontext_t;
53 #else
54 typedef int ucontext_t; // just to quiet the compiler, mostly
55 #endif
56 #include <sys/time.h>
57 #include <string>
58 #include <gperftools/profiler.h>
59 #include <gperftools/stacktrace.h>
60 #include "base/commandlineflags.h"
61 #include "base/logging.h"
62 #include "base/googleinit.h"
63 #include "base/spinlock.h"
64 #include "base/sysinfo.h" /* for GetUniquePathFromEnv, etc */
65 #include "profiledata.h"
66 #include "profile-handler.h"
67 #ifdef HAVE_CONFLICT_SIGNAL_H
68 #include "conflict-signal.h" /* used on msvc machines */
69 #endif
70
71 using std::string;
72
73 // Collects up all profile data. This is a singleton, which is
74 // initialized by a constructor at startup.
75 class CpuProfiler {
76 public:
77 CpuProfiler();
78 ~CpuProfiler();
79
80 // Start profiler to write profile info into fname
81 bool Start(const char* fname, const ProfilerOptions* options);
82
83 // Stop profiling and write the data to disk.
84 void Stop();
85
86 // Write the data to disk (and continue profiling).
87 void FlushTable();
88
89 bool Enabled();
90
91 void GetCurrentState(ProfilerState* state);
92
93 static CpuProfiler instance_;
94
95 private:
96 // This lock implements the locking requirements described in the ProfileData
97 // documentation, specifically:
98 //
99 // lock_ is held all over all collector_ method calls except for the 'Add'
100 // call made from the signal handler, to protect against concurrent use of
101 // collector_'s control routines. Code other than signal handler must
102 // unregister the signal handler before calling any collector_ method.
103 // 'Add' method in the collector is protected by a guarantee from
104 // ProfileHandle that only one instance of prof_handler can run at a time.
105 SpinLock lock_;
106 ProfileData collector_;
107
108 // Filter function and its argument, if any. (NULL means include all
109 // samples). Set at start, read-only while running. Written while holding
110 // lock_, read and executed in the context of SIGPROF interrupt.
111 int (*filter_)(void*);
112 void* filter_arg_;
113
114 // Opaque token returned by the profile handler. To be used when calling
115 // ProfileHandlerUnregisterCallback.
116 ProfileHandlerToken* prof_handler_token_;
117
118 // Sets up a callback to receive SIGPROF interrupt.
119 void EnableHandler();
120
121 // Disables receiving SIGPROF interrupt.
122 void DisableHandler();
123
124 // Signal handler that records the interrupted pc in the profile data.
125 static void prof_handler(int sig, siginfo_t*, void* signal_ucontext,
126 void* cpu_profiler);
127 };
128
129 // Profile data structure singleton: Constructor will check to see if
130 // profiling should be enabled. Destructor will write profile data
131 // out to disk.
132 CpuProfiler CpuProfiler::instance_;
133
134 // Initialize profiling: activated if getenv("CPUPROFILE") exists.
CpuProfiler()135 CpuProfiler::CpuProfiler()
136 : prof_handler_token_(NULL) {
137 // TODO(cgd) Move this code *out* of the CpuProfile constructor into a
138 // separate object responsible for initialization. With ProfileHandler there
139 // is no need to limit the number of profilers.
140 char fname[PATH_MAX];
141 if (!GetUniquePathFromEnv("CPUPROFILE", fname)) {
142 return;
143 }
144 // We don't enable profiling if setuid -- it's a security risk
145 #ifdef HAVE_GETEUID
146 if (getuid() != geteuid())
147 return;
148 #endif
149
150 if (!Start(fname, NULL)) {
151 RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
152 fname, strerror(errno));
153 }
154 }
155
Start(const char * fname,const ProfilerOptions * options)156 bool CpuProfiler::Start(const char* fname, const ProfilerOptions* options) {
157 SpinLockHolder cl(&lock_);
158
159 if (collector_.enabled()) {
160 return false;
161 }
162
163 ProfileHandlerState prof_handler_state;
164 ProfileHandlerGetState(&prof_handler_state);
165
166 ProfileData::Options collector_options;
167 collector_options.set_frequency(prof_handler_state.frequency);
168 if (!collector_.Start(fname, collector_options)) {
169 return false;
170 }
171
172 filter_ = NULL;
173 if (options != NULL && options->filter_in_thread != NULL) {
174 filter_ = options->filter_in_thread;
175 filter_arg_ = options->filter_in_thread_arg;
176 }
177
178 // Setup handler for SIGPROF interrupts
179 EnableHandler();
180
181 return true;
182 }
183
~CpuProfiler()184 CpuProfiler::~CpuProfiler() {
185 Stop();
186 }
187
188 // Stop profiling and write out any collected profile data
Stop()189 void CpuProfiler::Stop() {
190 SpinLockHolder cl(&lock_);
191
192 if (!collector_.enabled()) {
193 return;
194 }
195
196 // Unregister prof_handler to stop receiving SIGPROF interrupts before
197 // stopping the collector.
198 DisableHandler();
199
200 // DisableHandler waits for the currently running callback to complete and
201 // guarantees no future invocations. It is safe to stop the collector.
202 collector_.Stop();
203 }
204
FlushTable()205 void CpuProfiler::FlushTable() {
206 SpinLockHolder cl(&lock_);
207
208 if (!collector_.enabled()) {
209 return;
210 }
211
212 // Unregister prof_handler to stop receiving SIGPROF interrupts before
213 // flushing the profile data.
214 DisableHandler();
215
216 // DisableHandler waits for the currently running callback to complete and
217 // guarantees no future invocations. It is safe to flush the profile data.
218 collector_.FlushTable();
219
220 EnableHandler();
221 }
222
Enabled()223 bool CpuProfiler::Enabled() {
224 SpinLockHolder cl(&lock_);
225 return collector_.enabled();
226 }
227
GetCurrentState(ProfilerState * state)228 void CpuProfiler::GetCurrentState(ProfilerState* state) {
229 ProfileData::State collector_state;
230 {
231 SpinLockHolder cl(&lock_);
232 collector_.GetCurrentState(&collector_state);
233 }
234
235 state->enabled = collector_state.enabled;
236 state->start_time = static_cast<time_t>(collector_state.start_time);
237 state->samples_gathered = collector_state.samples_gathered;
238 int buf_size = sizeof(state->profile_name);
239 strncpy(state->profile_name, collector_state.profile_name, buf_size);
240 state->profile_name[buf_size-1] = '\0';
241 }
242
EnableHandler()243 void CpuProfiler::EnableHandler() {
244 RAW_CHECK(prof_handler_token_ == NULL, "SIGPROF handler already registered");
245 prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this);
246 RAW_CHECK(prof_handler_token_ != NULL, "Failed to set up SIGPROF handler");
247 }
248
DisableHandler()249 void CpuProfiler::DisableHandler() {
250 RAW_CHECK(prof_handler_token_ != NULL, "SIGPROF handler is not registered");
251 ProfileHandlerUnregisterCallback(prof_handler_token_);
252 prof_handler_token_ = NULL;
253 }
254
255 // Signal handler that records the pc in the profile-data structure. We do no
256 // synchronization here. profile-handler.cc guarantees that at most one
257 // instance of prof_handler() will run at a time. All other routines that
258 // access the data touched by prof_handler() disable this signal handler before
259 // accessing the data and therefore cannot execute concurrently with
260 // prof_handler().
prof_handler(int sig,siginfo_t *,void * signal_ucontext,void * cpu_profiler)261 void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext,
262 void* cpu_profiler) {
263 CpuProfiler* instance = static_cast<CpuProfiler*>(cpu_profiler);
264
265 if (instance->filter_ == NULL ||
266 (*instance->filter_)(instance->filter_arg_)) {
267 void* stack[ProfileData::kMaxStackDepth];
268
269 // The top-most active routine doesn't show up as a normal
270 // frame, but as the "pc" value in the signal handler context.
271 stack[0] = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext));
272
273 // We skip the top two stack trace entries (this function and one
274 // signal handler frame) since they are artifacts of profiling and
275 // should not be measured. Other profiling related frames may be
276 // removed by "pprof" at analysis time. Instead of skipping the top
277 // frames, we could skip nothing, but that would increase the
278 // profile size unnecessarily.
279 int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1,
280 2, signal_ucontext);
281 depth++; // To account for pc value in stack[0];
282
283 instance->collector_.Add(depth, stack);
284 }
285 }
286
287 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
288
ProfilerRegisterThread()289 extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() {
290 ProfileHandlerRegisterThread();
291 }
292
ProfilerFlush()293 extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
294 CpuProfiler::instance_.FlushTable();
295 }
296
ProfilingIsEnabledForAllThreads()297 extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
298 return CpuProfiler::instance_.Enabled();
299 }
300
ProfilerStart(const char * fname)301 extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) {
302 return CpuProfiler::instance_.Start(fname, NULL);
303 }
304
ProfilerStartWithOptions(const char * fname,const ProfilerOptions * options)305 extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions(
306 const char *fname, const ProfilerOptions *options) {
307 return CpuProfiler::instance_.Start(fname, options);
308 }
309
ProfilerStop()310 extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() {
311 CpuProfiler::instance_.Stop();
312 }
313
ProfilerGetCurrentState(ProfilerState * state)314 extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState(
315 ProfilerState* state) {
316 CpuProfiler::instance_.GetCurrentState(state);
317 }
318
319 #else // OS_CYGWIN
320
321 // ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't
322 // work as well for profiling, and also interferes with alarm(). Because of
323 // these issues, unless a specific need is identified, profiler support is
324 // disabled under Cygwin.
ProfilerRegisterThread()325 extern "C" void ProfilerRegisterThread() { }
ProfilerFlush()326 extern "C" void ProfilerFlush() { }
ProfilingIsEnabledForAllThreads()327 extern "C" int ProfilingIsEnabledForAllThreads() { return 0; }
ProfilerStart(const char * fname)328 extern "C" int ProfilerStart(const char* fname) { return 0; }
ProfilerStartWithOptions(const char * fname,const ProfilerOptions * options)329 extern "C" int ProfilerStartWithOptions(const char *fname,
330 const ProfilerOptions *options) {
331 return 0;
332 }
ProfilerStop()333 extern "C" void ProfilerStop() { }
ProfilerGetCurrentState(ProfilerState * state)334 extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
335 memset(state, 0, sizeof(*state));
336 }
337
338 #endif // OS_CYGWIN
339
340 // DEPRECATED routines
ProfilerEnable()341 extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { }
ProfilerDisable()342 extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { }
343