Home | History | Annotate | Download | only in src
      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.
    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 
    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 
    186 CpuProfiler::~CpuProfiler() {
    187   Stop();
    188 }
    189 
    190 // Stop profiling and write out any collected profile data
    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 
    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 
    225 bool CpuProfiler::Enabled() {
    226   SpinLockHolder cl(&lock_);
    227   return collector_.enabled();
    228 }
    229 
    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 
    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 
    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().
    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 
    291 extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() {
    292   ProfileHandlerRegisterThread();
    293 }
    294 
    295 extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
    296   CpuProfiler::instance_.FlushTable();
    297 }
    298 
    299 extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
    300   return CpuProfiler::instance_.Enabled();
    301 }
    302 
    303 extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) {
    304   return CpuProfiler::instance_.Start(fname, NULL);
    305 }
    306 
    307 extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions(
    308     const char *fname, const ProfilerOptions *options) {
    309   return CpuProfiler::instance_.Start(fname, options);
    310 }
    311 
    312 extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() {
    313   CpuProfiler::instance_.Stop();
    314 }
    315 
    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.
    327 extern "C" void ProfilerRegisterThread() { }
    328 extern "C" void ProfilerFlush() { }
    329 extern "C" int ProfilingIsEnabledForAllThreads() { return 0; }
    330 extern "C" int ProfilerStart(const char* fname) { return 0; }
    331 extern "C" int ProfilerStartWithOptions(const char *fname,
    332                                         const ProfilerOptions *options) {
    333   return 0;
    334 }
    335 extern "C" void ProfilerStop() { }
    336 extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
    337   memset(state, 0, sizeof(*state));
    338 }
    339 
    340 #endif  // OS_CYGWIN
    341 
    342 // DEPRECATED routines
    343 extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { }
    344 extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { }
    345