15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2005, Google Inc.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met:
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions of source code must retain the above copyright
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions in binary form must reproduce the above
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Neither the name of Google Inc. nor the names of its
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ---
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Sanjay Ghemawat
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         Chris Demetriou (refactoring)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Profile current program by sampling stack-trace every so often
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "config.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "getpc.h"      // should be first to get the _GNU_SOURCE dfn
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <signal.h>
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h>
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_UNISTD_H
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>  // for getpid()
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(HAVE_SYS_UCONTEXT_H)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/ucontext.h>
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(HAVE_UCONTEXT_H)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ucontext.h>
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(HAVE_CYGWIN_SIGNAL_H)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cygwin/signal.h>
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef ucontext ucontext_t;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef int ucontext_t;   // just to quiet the compiler, mostly
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/time.h>
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gperftools/profiler.h>
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gperftools/stacktrace.h>
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/commandlineflags.h"
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/googleinit.h"
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/spinlock.h"
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sysinfo.h"             /* for GetUniquePathFromEnv, etc */
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "profiledata.h"
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "profile-handler.h"
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_CONFLICT_SIGNAL_H
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "conflict-signal.h"          /* used on msvc machines */
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Collects up all profile data.  This is a singleton, which is
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// initialized by a constructor at startup.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CpuProfiler {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CpuProfiler();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~CpuProfiler();
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start profiler to write profile info into fname
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Start(const char* fname, const ProfilerOptions* options);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stop profiling and write the data to disk.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Stop();
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Write the data to disk (and continue profiling).
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void FlushTable();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Enabled();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void GetCurrentState(ProfilerState* state);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static CpuProfiler instance_;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This lock implements the locking requirements described in the ProfileData
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // documentation, specifically:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // lock_ is held all over all collector_ method calls except for the 'Add'
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // call made from the signal handler, to protect against concurrent use of
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // collector_'s control routines. Code other than signal handler must
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // unregister the signal handler before calling any collector_ method.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 'Add' method in the collector is protected by a guarantee from
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ProfileHandle that only one instance of prof_handler can run at a time.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SpinLock      lock_;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileData   collector_;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Filter function and its argument, if any.  (NULL means include all
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // samples).  Set at start, read-only while running.  Written while holding
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // lock_, read and executed in the context of SIGPROF interrupt.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int           (*filter_)(void*);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void*         filter_arg_;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Opaque token returned by the profile handler. To be used when calling
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ProfileHandlerUnregisterCallback.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileHandlerToken* prof_handler_token_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets up a callback to receive SIGPROF interrupt.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void EnableHandler();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disables receiving SIGPROF interrupt.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DisableHandler();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Signal handler that records the interrupted pc in the profile data.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void prof_handler(int sig, siginfo_t*, void* signal_ucontext,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           void* cpu_profiler);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Profile data structure singleton: Constructor will check to see if
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// profiling should be enabled.  Destructor will write profile data
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// out to disk.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CpuProfiler CpuProfiler::instance_;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Initialize profiling: activated if getenv("CPUPROFILE") exists.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CpuProfiler::CpuProfiler()
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : prof_handler_token_(NULL) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(cgd) Move this code *out* of the CpuProfile constructor into a
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // separate object responsible for initialization. With ProfileHandler there
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is no need to limit the number of profilers.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char fname[PATH_MAX];
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetUniquePathFromEnv("CPUPROFILE", fname)) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't enable profiling if setuid -- it's a security risk
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_GETEUID
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (getuid() != geteuid())
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!Start(fname, NULL)) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fname, strerror(errno));
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CpuProfiler::Start(const char* fname, const ProfilerOptions* options) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SpinLockHolder cl(&lock_);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (collector_.enabled()) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileHandlerState prof_handler_state;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileHandlerGetState(&prof_handler_state);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileData::Options collector_options;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  collector_options.set_frequency(prof_handler_state.frequency);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!collector_.Start(fname, collector_options)) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filter_ = NULL;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (options != NULL && options->filter_in_thread != NULL) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filter_ = options->filter_in_thread;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filter_arg_ = options->filter_in_thread_arg;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Setup handler for SIGPROF interrupts
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnableHandler();
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CpuProfiler::~CpuProfiler() {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Stop();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Stop profiling and write out any collected profile data
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CpuProfiler::Stop() {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SpinLockHolder cl(&lock_);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!collector_.enabled()) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unregister prof_handler to stop receiving SIGPROF interrupts before
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // stopping the collector.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DisableHandler();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DisableHandler waits for the currently running callback to complete and
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // guarantees no future invocations. It is safe to stop the collector.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  collector_.Stop();
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CpuProfiler::FlushTable() {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SpinLockHolder cl(&lock_);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!collector_.enabled()) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unregister prof_handler to stop receiving SIGPROF interrupts before
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // flushing the profile data.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DisableHandler();
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DisableHandler waits for the currently running callback to complete and
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // guarantees no future invocations. It is safe to flush the profile data.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  collector_.FlushTable();
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnableHandler();
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CpuProfiler::Enabled() {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SpinLockHolder cl(&lock_);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return collector_.enabled();
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CpuProfiler::GetCurrentState(ProfilerState* state) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileData::State collector_state;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SpinLockHolder cl(&lock_);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    collector_.GetCurrentState(&collector_state);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->enabled = collector_state.enabled;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->start_time = static_cast<time_t>(collector_state.start_time);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->samples_gathered = collector_state.samples_gathered;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int buf_size = sizeof(state->profile_name);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  strncpy(state->profile_name, collector_state.profile_name, buf_size);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->profile_name[buf_size-1] = '\0';
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CpuProfiler::EnableHandler() {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RAW_CHECK(prof_handler_token_ == NULL, "SIGPROF handler already registered");
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RAW_CHECK(prof_handler_token_ != NULL, "Failed to set up SIGPROF handler");
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CpuProfiler::DisableHandler() {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RAW_CHECK(prof_handler_token_ != NULL, "SIGPROF handler is not registered");
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileHandlerUnregisterCallback(prof_handler_token_);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prof_handler_token_ = NULL;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Signal handler that records the pc in the profile-data structure. We do no
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// synchronization here.  profile-handler.cc guarantees that at most one
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// instance of prof_handler() will run at a time. All other routines that
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// access the data touched by prof_handler() disable this signal handler before
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// accessing the data and therefore cannot execute concurrently with
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// prof_handler().
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext,
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               void* cpu_profiler) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CpuProfiler* instance = static_cast<CpuProfiler*>(cpu_profiler);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (instance->filter_ == NULL ||
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*instance->filter_)(instance->filter_arg_)) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* stack[ProfileData::kMaxStackDepth];
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The top-most active routine doesn't show up as a normal
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // frame, but as the "pc" value in the signal handler context.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stack[0] = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext));
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We skip the top two stack trace entries (this function and one
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // signal handler frame) since they are artifacts of profiling and
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // should not be measured.  Other profiling related frames may be
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // removed by "pprof" at analysis time.  Instead of skipping the top
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // frames, we could skip nothing, but that would increase the
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // profile size unnecessarily.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         2, signal_ucontext);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    depth++;  // To account for pc value in stack[0];
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    instance->collector_.Add(depth, stack);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileHandlerRegisterThread();
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CpuProfiler::instance_.FlushTable();
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CpuProfiler::instance_.Enabled();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CpuProfiler::instance_.Start(fname, NULL);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions(
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char *fname, const ProfilerOptions *options) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CpuProfiler::instance_.Start(fname, options);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CpuProfiler::instance_.Stop();
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState(
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfilerState* state) {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CpuProfiler::instance_.GetCurrentState(state);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else  // OS_CYGWIN
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ITIMER_PROF doesn't work under cygwin.  ITIMER_REAL is available, but doesn't
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// work as well for profiling, and also interferes with alarm().  Because of
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// these issues, unless a specific need is identified, profiler support is
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// disabled under Cygwin.
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfilerRegisterThread() { }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfilerFlush() { }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" int ProfilingIsEnabledForAllThreads() { return 0; }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" int ProfilerStart(const char* fname) { return 0; }
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" int ProfilerStartWithOptions(const char *fname,
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        const ProfilerOptions *options) {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfilerStop() { }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(state, 0, sizeof(*state));
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // OS_CYGWIN
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DEPRECATED routines
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { }
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { }
343