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> 52typedef ucontext ucontext_t; 53#else 54typedef 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 71using std::string; 72 73// Collects up all profile data. This is a singleton, which is 74// initialized by a constructor at startup. 75class 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. 132CpuProfiler CpuProfiler::instance_; 133 134// Initialize profiling: activated if getenv("CPUPROFILE") exists. 135CpuProfiler::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 156bool 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 184CpuProfiler::~CpuProfiler() { 185 Stop(); 186} 187 188// Stop profiling and write out any collected profile data 189void 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 205void 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 223bool CpuProfiler::Enabled() { 224 SpinLockHolder cl(&lock_); 225 return collector_.enabled(); 226} 227 228void 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 243void 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 249void 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(). 261void 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 289extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() { 290 ProfileHandlerRegisterThread(); 291} 292 293extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() { 294 CpuProfiler::instance_.FlushTable(); 295} 296 297extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() { 298 return CpuProfiler::instance_.Enabled(); 299} 300 301extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) { 302 return CpuProfiler::instance_.Start(fname, NULL); 303} 304 305extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions( 306 const char *fname, const ProfilerOptions *options) { 307 return CpuProfiler::instance_.Start(fname, options); 308} 309 310extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() { 311 CpuProfiler::instance_.Stop(); 312} 313 314extern "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. 325extern "C" void ProfilerRegisterThread() { } 326extern "C" void ProfilerFlush() { } 327extern "C" int ProfilingIsEnabledForAllThreads() { return 0; } 328extern "C" int ProfilerStart(const char* fname) { return 0; } 329extern "C" int ProfilerStartWithOptions(const char *fname, 330 const ProfilerOptions *options) { 331 return 0; 332} 333extern "C" void ProfilerStop() { } 334extern "C" void ProfilerGetCurrentState(ProfilerState* state) { 335 memset(state, 0, sizeof(*state)); 336} 337 338#endif // OS_CYGWIN 339 340// DEPRECATED routines 341extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { } 342extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { } 343