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