• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #elif defined(__ANDROID__)
54 // Do not define ucontext_t here.
55 #else
56 typedef int ucontext_t;   // just to quiet the compiler, mostly
57 #endif
58 #include <sys/time.h>
59 #include <string>
60 #include <gperftools/profiler.h>
61 #include <gperftools/stacktrace.h>
62 #include "base/commandlineflags.h"
63 #include "base/logging.h"
64 #include "base/googleinit.h"
65 #include "base/spinlock.h"
66 #include "base/sysinfo.h"             /* for GetUniquePathFromEnv, etc */
67 #include "profiledata.h"
68 #include "profile-handler.h"
69 #ifdef HAVE_CONFLICT_SIGNAL_H
70 #include "conflict-signal.h"          /* used on msvc machines */
71 #endif
72 
73 using std::string;
74 
75 // Collects up all profile data.  This is a singleton, which is
76 // initialized by a constructor at startup.
77 class CpuProfiler {
78  public:
79   CpuProfiler();
80   ~CpuProfiler();
81 
82   // Start profiler to write profile info into fname
83   bool Start(const char* fname, const ProfilerOptions* options);
84 
85   // Stop profiling and write the data to disk.
86   void Stop();
87 
88   // Write the data to disk (and continue profiling).
89   void FlushTable();
90 
91   bool Enabled();
92 
93   void GetCurrentState(ProfilerState* state);
94 
95   static CpuProfiler instance_;
96 
97  private:
98   // This lock implements the locking requirements described in the ProfileData
99   // documentation, specifically:
100   //
101   // lock_ is held all over all collector_ method calls except for the 'Add'
102   // call made from the signal handler, to protect against concurrent use of
103   // collector_'s control routines. Code other than signal handler must
104   // unregister the signal handler before calling any collector_ method.
105   // 'Add' method in the collector is protected by a guarantee from
106   // ProfileHandle that only one instance of prof_handler can run at a time.
107   SpinLock      lock_;
108   ProfileData   collector_;
109 
110   // Filter function and its argument, if any.  (NULL means include all
111   // samples).  Set at start, read-only while running.  Written while holding
112   // lock_, read and executed in the context of SIGPROF interrupt.
113   int           (*filter_)(void*);
114   void*         filter_arg_;
115 
116   // Opaque token returned by the profile handler. To be used when calling
117   // ProfileHandlerUnregisterCallback.
118   ProfileHandlerToken* prof_handler_token_;
119 
120   // Sets up a callback to receive SIGPROF interrupt.
121   void EnableHandler();
122 
123   // Disables receiving SIGPROF interrupt.
124   void DisableHandler();
125 
126   // Signal handler that records the interrupted pc in the profile data.
127   static void prof_handler(int sig, siginfo_t*, void* signal_ucontext,
128                            void* cpu_profiler);
129 };
130 
131 // Profile data structure singleton: Constructor will check to see if
132 // profiling should be enabled.  Destructor will write profile data
133 // out to disk.
134 CpuProfiler CpuProfiler::instance_;
135 
136 // Initialize profiling: activated if getenv("CPUPROFILE") exists.
CpuProfiler()137 CpuProfiler::CpuProfiler()
138     : prof_handler_token_(NULL) {
139   // TODO(cgd) Move this code *out* of the CpuProfile constructor into a
140   // separate object responsible for initialization. With ProfileHandler there
141   // is no need to limit the number of profilers.
142   char fname[PATH_MAX];
143   if (!GetUniquePathFromEnv("CPUPROFILE", fname)) {
144     return;
145   }
146   // We don't enable profiling if setuid -- it's a security risk
147 #ifdef HAVE_GETEUID
148   if (getuid() != geteuid())
149     return;
150 #endif
151 
152   if (!Start(fname, NULL)) {
153     RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
154             fname, strerror(errno));
155   }
156 }
157 
Start(const char * fname,const ProfilerOptions * options)158 bool CpuProfiler::Start(const char* fname, const ProfilerOptions* options) {
159   SpinLockHolder cl(&lock_);
160 
161   if (collector_.enabled()) {
162     return false;
163   }
164 
165   ProfileHandlerState prof_handler_state;
166   ProfileHandlerGetState(&prof_handler_state);
167 
168   ProfileData::Options collector_options;
169   collector_options.set_frequency(prof_handler_state.frequency);
170   if (!collector_.Start(fname, collector_options)) {
171     return false;
172   }
173 
174   filter_ = NULL;
175   if (options != NULL && options->filter_in_thread != NULL) {
176     filter_ = options->filter_in_thread;
177     filter_arg_ = options->filter_in_thread_arg;
178   }
179 
180   // Setup handler for SIGPROF interrupts
181   EnableHandler();
182 
183   return true;
184 }
185 
~CpuProfiler()186 CpuProfiler::~CpuProfiler() {
187   Stop();
188 }
189 
190 // Stop profiling and write out any collected profile data
Stop()191 void CpuProfiler::Stop() {
192   SpinLockHolder cl(&lock_);
193 
194   if (!collector_.enabled()) {
195     return;
196   }
197 
198   // Unregister prof_handler to stop receiving SIGPROF interrupts before
199   // stopping the collector.
200   DisableHandler();
201 
202   // DisableHandler waits for the currently running callback to complete and
203   // guarantees no future invocations. It is safe to stop the collector.
204   collector_.Stop();
205 }
206 
FlushTable()207 void CpuProfiler::FlushTable() {
208   SpinLockHolder cl(&lock_);
209 
210   if (!collector_.enabled()) {
211     return;
212   }
213 
214   // Unregister prof_handler to stop receiving SIGPROF interrupts before
215   // flushing the profile data.
216   DisableHandler();
217 
218   // DisableHandler waits for the currently running callback to complete and
219   // guarantees no future invocations. It is safe to flush the profile data.
220   collector_.FlushTable();
221 
222   EnableHandler();
223 }
224 
Enabled()225 bool CpuProfiler::Enabled() {
226   SpinLockHolder cl(&lock_);
227   return collector_.enabled();
228 }
229 
GetCurrentState(ProfilerState * state)230 void CpuProfiler::GetCurrentState(ProfilerState* state) {
231   ProfileData::State collector_state;
232   {
233     SpinLockHolder cl(&lock_);
234     collector_.GetCurrentState(&collector_state);
235   }
236 
237   state->enabled = collector_state.enabled;
238   state->start_time = static_cast<time_t>(collector_state.start_time);
239   state->samples_gathered = collector_state.samples_gathered;
240   int buf_size = sizeof(state->profile_name);
241   strncpy(state->profile_name, collector_state.profile_name, buf_size);
242   state->profile_name[buf_size-1] = '\0';
243 }
244 
EnableHandler()245 void CpuProfiler::EnableHandler() {
246   RAW_CHECK(prof_handler_token_ == NULL, "SIGPROF handler already registered");
247   prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this);
248   RAW_CHECK(prof_handler_token_ != NULL, "Failed to set up SIGPROF handler");
249 }
250 
DisableHandler()251 void CpuProfiler::DisableHandler() {
252   RAW_CHECK(prof_handler_token_ != NULL, "SIGPROF handler is not registered");
253   ProfileHandlerUnregisterCallback(prof_handler_token_);
254   prof_handler_token_ = NULL;
255 }
256 
257 // Signal handler that records the pc in the profile-data structure. We do no
258 // synchronization here.  profile-handler.cc guarantees that at most one
259 // instance of prof_handler() will run at a time. All other routines that
260 // access the data touched by prof_handler() disable this signal handler before
261 // accessing the data and therefore cannot execute concurrently with
262 // prof_handler().
prof_handler(int sig,siginfo_t *,void * signal_ucontext,void * cpu_profiler)263 void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext,
264                                void* cpu_profiler) {
265   CpuProfiler* instance = static_cast<CpuProfiler*>(cpu_profiler);
266 
267   if (instance->filter_ == NULL ||
268       (*instance->filter_)(instance->filter_arg_)) {
269     void* stack[ProfileData::kMaxStackDepth];
270 
271     // The top-most active routine doesn't show up as a normal
272     // frame, but as the "pc" value in the signal handler context.
273     stack[0] = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext));
274 
275     // We skip the top two stack trace entries (this function and one
276     // signal handler frame) since they are artifacts of profiling and
277     // should not be measured.  Other profiling related frames may be
278     // removed by "pprof" at analysis time.  Instead of skipping the top
279     // frames, we could skip nothing, but that would increase the
280     // profile size unnecessarily.
281     int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1,
282                                          2, signal_ucontext);
283     depth++;  // To account for pc value in stack[0];
284 
285     instance->collector_.Add(depth, stack);
286   }
287 }
288 
289 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
290 
ProfilerRegisterThread()291 extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() {
292   ProfileHandlerRegisterThread();
293 }
294 
ProfilerFlush()295 extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
296   CpuProfiler::instance_.FlushTable();
297 }
298 
ProfilingIsEnabledForAllThreads()299 extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
300   return CpuProfiler::instance_.Enabled();
301 }
302 
ProfilerStart(const char * fname)303 extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) {
304   return CpuProfiler::instance_.Start(fname, NULL);
305 }
306 
ProfilerStartWithOptions(const char * fname,const ProfilerOptions * options)307 extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions(
308     const char *fname, const ProfilerOptions *options) {
309   return CpuProfiler::instance_.Start(fname, options);
310 }
311 
ProfilerStop()312 extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() {
313   CpuProfiler::instance_.Stop();
314 }
315 
ProfilerGetCurrentState(ProfilerState * state)316 extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState(
317     ProfilerState* state) {
318   CpuProfiler::instance_.GetCurrentState(state);
319 }
320 
321 #else  // OS_CYGWIN
322 
323 // ITIMER_PROF doesn't work under cygwin.  ITIMER_REAL is available, but doesn't
324 // work as well for profiling, and also interferes with alarm().  Because of
325 // these issues, unless a specific need is identified, profiler support is
326 // disabled under Cygwin.
ProfilerRegisterThread()327 extern "C" void ProfilerRegisterThread() { }
ProfilerFlush()328 extern "C" void ProfilerFlush() { }
ProfilingIsEnabledForAllThreads()329 extern "C" int ProfilingIsEnabledForAllThreads() { return 0; }
ProfilerStart(const char * fname)330 extern "C" int ProfilerStart(const char* fname) { return 0; }
ProfilerStartWithOptions(const char * fname,const ProfilerOptions * options)331 extern "C" int ProfilerStartWithOptions(const char *fname,
332                                         const ProfilerOptions *options) {
333   return 0;
334 }
ProfilerStop()335 extern "C" void ProfilerStop() { }
ProfilerGetCurrentState(ProfilerState * state)336 extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
337   memset(state, 0, sizeof(*state));
338 }
339 
340 #endif  // OS_CYGWIN
341 
342 // DEPRECATED routines
ProfilerEnable()343 extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { }
ProfilerDisable()344 extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { }
345