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#elif defined(__ANDROID__) 54// Do not define ucontext_t here. 55#else 56typedef 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 73using std::string; 74 75// Collects up all profile data. This is a singleton, which is 76// initialized by a constructor at startup. 77class 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. 134CpuProfiler CpuProfiler::instance_; 135 136// Initialize profiling: activated if getenv("CPUPROFILE") exists. 137CpuProfiler::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 158bool 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 186CpuProfiler::~CpuProfiler() { 187 Stop(); 188} 189 190// Stop profiling and write out any collected profile data 191void 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 207void 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 225bool CpuProfiler::Enabled() { 226 SpinLockHolder cl(&lock_); 227 return collector_.enabled(); 228} 229 230void 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 245void 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 251void 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(). 263void 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 291extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() { 292 ProfileHandlerRegisterThread(); 293} 294 295extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() { 296 CpuProfiler::instance_.FlushTable(); 297} 298 299extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() { 300 return CpuProfiler::instance_.Enabled(); 301} 302 303extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) { 304 return CpuProfiler::instance_.Start(fname, NULL); 305} 306 307extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions( 308 const char *fname, const ProfilerOptions *options) { 309 return CpuProfiler::instance_.Start(fname, options); 310} 311 312extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() { 313 CpuProfiler::instance_.Stop(); 314} 315 316extern "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. 327extern "C" void ProfilerRegisterThread() { } 328extern "C" void ProfilerFlush() { } 329extern "C" int ProfilingIsEnabledForAllThreads() { return 0; } 330extern "C" int ProfilerStart(const char* fname) { return 0; } 331extern "C" int ProfilerStartWithOptions(const char *fname, 332 const ProfilerOptions *options) { 333 return 0; 334} 335extern "C" void ProfilerStop() { } 336extern "C" void ProfilerGetCurrentState(ProfilerState* state) { 337 memset(state, 0, sizeof(*state)); 338} 339 340#endif // OS_CYGWIN 341 342// DEPRECATED routines 343extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { } 344extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { } 345