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