Austin Schuh | 745610d | 2015-09-06 18:19:50 -0700 | [diff] [blame] | 1 | // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- |
| 2 | // Copyright (c) 2005, Google Inc. |
| 3 | // All rights reserved. |
| 4 | // |
| 5 | // Redistribution and use in source and binary forms, with or without |
| 6 | // modification, are permitted provided that the following conditions are |
| 7 | // met: |
| 8 | // |
| 9 | // * Redistributions of source code must retain the above copyright |
| 10 | // notice, this list of conditions and the following disclaimer. |
| 11 | // * Redistributions in binary form must reproduce the above |
| 12 | // copyright notice, this list of conditions and the following disclaimer |
| 13 | // in the documentation and/or other materials provided with the |
| 14 | // distribution. |
| 15 | // * Neither the name of Google Inc. nor the names of its |
| 16 | // contributors may be used to endorse or promote products derived from |
| 17 | // this software without specific prior written permission. |
| 18 | // |
| 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | |
| 31 | // --- |
| 32 | // Author: Sanjay Ghemawat |
| 33 | // Chris Demetriou (refactoring) |
| 34 | // |
| 35 | // Profile current program by sampling stack-trace every so often |
| 36 | |
| 37 | #include "config.h" |
| 38 | #include "getpc.h" // should be first to get the _GNU_SOURCE dfn |
| 39 | #include <signal.h> |
| 40 | #include <assert.h> |
| 41 | #include <stdio.h> |
| 42 | #include <errno.h> |
| 43 | #include <string.h> |
| 44 | #ifdef HAVE_UNISTD_H |
| 45 | #include <unistd.h> // for getpid() |
| 46 | #endif |
| 47 | #if defined(HAVE_SYS_UCONTEXT_H) |
| 48 | #include <sys/ucontext.h> |
| 49 | #elif defined(HAVE_UCONTEXT_H) |
| 50 | #include <ucontext.h> |
| 51 | #elif defined(HAVE_CYGWIN_SIGNAL_H) |
| 52 | #include <cygwin/signal.h> |
| 53 | typedef ucontext ucontext_t; |
| 54 | #else |
| 55 | typedef int ucontext_t; // just to quiet the compiler, mostly |
| 56 | #endif |
| 57 | #include <sys/time.h> |
| 58 | #include <string> |
| 59 | #include <gperftools/profiler.h> |
| 60 | #include <gperftools/stacktrace.h> |
| 61 | #include "base/commandlineflags.h" |
| 62 | #include "base/logging.h" |
| 63 | #include "base/googleinit.h" |
| 64 | #include "base/spinlock.h" |
| 65 | #include "base/sysinfo.h" /* for GetUniquePathFromEnv, etc */ |
| 66 | #include "profiledata.h" |
| 67 | #include "profile-handler.h" |
| 68 | #ifdef HAVE_CONFLICT_SIGNAL_H |
| 69 | #include "conflict-signal.h" /* used on msvc machines */ |
| 70 | #endif |
| 71 | |
| 72 | using std::string; |
| 73 | |
| 74 | DEFINE_bool(cpu_profiler_unittest, |
| 75 | EnvToBool("PERFTOOLS_UNITTEST", true), |
| 76 | "Determines whether or not we are running under the \ |
| 77 | control of a unit test. This allows us to include or \ |
| 78 | exclude certain behaviours."); |
| 79 | |
| 80 | // Collects up all profile data. This is a singleton, which is |
| 81 | // initialized by a constructor at startup. If no cpu profiler |
| 82 | // signal is specified then the profiler lifecycle is either |
| 83 | // manaully controlled via the API or attached to the scope of |
| 84 | // the singleton (program scope). Otherwise the cpu toggle is |
| 85 | // used to allow for user selectable control via signal generation. |
| 86 | // This is very useful for profiling a daemon process without |
| 87 | // having to start and stop the daemon or having to modify the |
| 88 | // source code to use the cpu profiler API. |
| 89 | class CpuProfiler { |
| 90 | public: |
| 91 | CpuProfiler(); |
| 92 | ~CpuProfiler(); |
| 93 | |
| 94 | // Start profiler to write profile info into fname |
| 95 | bool Start(const char* fname, const ProfilerOptions* options); |
| 96 | |
| 97 | // Stop profiling and write the data to disk. |
| 98 | void Stop(); |
| 99 | |
| 100 | // Write the data to disk (and continue profiling). |
| 101 | void FlushTable(); |
| 102 | |
| 103 | bool Enabled(); |
| 104 | |
| 105 | void GetCurrentState(ProfilerState* state); |
| 106 | |
| 107 | static CpuProfiler instance_; |
| 108 | |
| 109 | private: |
| 110 | // This lock implements the locking requirements described in the ProfileData |
| 111 | // documentation, specifically: |
| 112 | // |
| 113 | // lock_ is held all over all collector_ method calls except for the 'Add' |
| 114 | // call made from the signal handler, to protect against concurrent use of |
| 115 | // collector_'s control routines. Code other than signal handler must |
| 116 | // unregister the signal handler before calling any collector_ method. |
| 117 | // 'Add' method in the collector is protected by a guarantee from |
| 118 | // ProfileHandle that only one instance of prof_handler can run at a time. |
| 119 | SpinLock lock_; |
| 120 | ProfileData collector_; |
| 121 | |
| 122 | // Filter function and its argument, if any. (NULL means include all |
| 123 | // samples). Set at start, read-only while running. Written while holding |
| 124 | // lock_, read and executed in the context of SIGPROF interrupt. |
| 125 | int (*filter_)(void*); |
| 126 | void* filter_arg_; |
| 127 | |
| 128 | // Opaque token returned by the profile handler. To be used when calling |
| 129 | // ProfileHandlerUnregisterCallback. |
| 130 | ProfileHandlerToken* prof_handler_token_; |
| 131 | |
| 132 | // Sets up a callback to receive SIGPROF interrupt. |
| 133 | void EnableHandler(); |
| 134 | |
| 135 | // Disables receiving SIGPROF interrupt. |
| 136 | void DisableHandler(); |
| 137 | |
| 138 | // Signal handler that records the interrupted pc in the profile data. |
| 139 | static void prof_handler(int sig, siginfo_t*, void* signal_ucontext, |
| 140 | void* cpu_profiler); |
| 141 | }; |
| 142 | |
| 143 | // Signal handler that is registered when a user selectable signal |
| 144 | // number is defined in the environment variable CPUPROFILESIGNAL. |
| 145 | static void CpuProfilerSwitch(int signal_number) |
| 146 | { |
| 147 | bool static started = false; |
| 148 | static unsigned profile_count = 0; |
| 149 | static char base_profile_name[1024] = "\0"; |
| 150 | |
| 151 | if (base_profile_name[0] == '\0') { |
| 152 | if (!GetUniquePathFromEnv("CPUPROFILE", base_profile_name)) { |
| 153 | RAW_LOG(FATAL,"Cpu profiler switch is registered but no CPUPROFILE is defined"); |
| 154 | return; |
| 155 | } |
| 156 | } |
| 157 | if (!started) |
| 158 | { |
| 159 | char full_profile_name[1024]; |
| 160 | |
| 161 | snprintf(full_profile_name, sizeof(full_profile_name), "%s.%u", |
| 162 | base_profile_name, profile_count++); |
| 163 | |
| 164 | if(!ProfilerStart(full_profile_name)) |
| 165 | { |
| 166 | RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n", |
| 167 | full_profile_name, strerror(errno)); |
| 168 | } |
| 169 | } |
| 170 | else |
| 171 | { |
| 172 | ProfilerStop(); |
| 173 | } |
| 174 | started = !started; |
| 175 | } |
| 176 | |
| 177 | // Profile data structure singleton: Constructor will check to see if |
| 178 | // profiling should be enabled. Destructor will write profile data |
| 179 | // out to disk. |
| 180 | CpuProfiler CpuProfiler::instance_; |
| 181 | |
| 182 | // Initialize profiling: activated if getenv("CPUPROFILE") exists. |
| 183 | CpuProfiler::CpuProfiler() |
| 184 | : prof_handler_token_(NULL) { |
| 185 | // TODO(cgd) Move this code *out* of the CpuProfile constructor into a |
| 186 | // separate object responsible for initialization. With ProfileHandler there |
| 187 | // is no need to limit the number of profilers. |
| 188 | if (getenv("CPUPROFILE") == NULL) { |
| 189 | if (!FLAGS_cpu_profiler_unittest) { |
| 190 | RAW_LOG(WARNING, "CPU profiler linked but no valid CPUPROFILE environment variable found\n"); |
| 191 | } |
| 192 | return; |
| 193 | } |
| 194 | |
| 195 | // We don't enable profiling if setuid -- it's a security risk |
| 196 | #ifdef HAVE_GETEUID |
| 197 | if (getuid() != geteuid()) { |
| 198 | if (!FLAGS_cpu_profiler_unittest) { |
| 199 | RAW_LOG(WARNING, "Cannot perform CPU profiling when running with setuid\n"); |
| 200 | } |
| 201 | return; |
| 202 | } |
| 203 | #endif |
| 204 | |
| 205 | char *signal_number_str = getenv("CPUPROFILESIGNAL"); |
| 206 | if (signal_number_str != NULL) { |
| 207 | long int signal_number = strtol(signal_number_str, NULL, 10); |
| 208 | if (signal_number >= 1 && signal_number <= 64) { |
| 209 | intptr_t old_signal_handler = reinterpret_cast<intptr_t>(signal(signal_number, CpuProfilerSwitch)); |
| 210 | if (old_signal_handler == 0) { |
| 211 | RAW_LOG(INFO,"Using signal %d as cpu profiling switch", signal_number); |
| 212 | } else { |
| 213 | RAW_LOG(FATAL, "Signal %d already in use\n", signal_number); |
| 214 | } |
| 215 | } else { |
| 216 | RAW_LOG(FATAL, "Signal number %s is invalid\n", signal_number_str); |
| 217 | } |
| 218 | } else { |
| 219 | char fname[PATH_MAX]; |
| 220 | if (!GetUniquePathFromEnv("CPUPROFILE", fname)) { |
| 221 | if (!FLAGS_cpu_profiler_unittest) { |
| 222 | RAW_LOG(WARNING, "CPU profiler linked but no valid CPUPROFILE environment variable found\n"); |
| 223 | } |
| 224 | return; |
| 225 | } |
| 226 | |
| 227 | if (!Start(fname, NULL)) { |
| 228 | RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n", |
| 229 | fname, strerror(errno)); |
| 230 | } |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | bool CpuProfiler::Start(const char* fname, const ProfilerOptions* options) { |
| 235 | SpinLockHolder cl(&lock_); |
| 236 | |
| 237 | if (collector_.enabled()) { |
| 238 | return false; |
| 239 | } |
| 240 | |
| 241 | ProfileHandlerState prof_handler_state; |
| 242 | ProfileHandlerGetState(&prof_handler_state); |
| 243 | |
| 244 | ProfileData::Options collector_options; |
| 245 | collector_options.set_frequency(prof_handler_state.frequency); |
| 246 | if (!collector_.Start(fname, collector_options)) { |
| 247 | return false; |
| 248 | } |
| 249 | |
| 250 | filter_ = NULL; |
| 251 | if (options != NULL && options->filter_in_thread != NULL) { |
| 252 | filter_ = options->filter_in_thread; |
| 253 | filter_arg_ = options->filter_in_thread_arg; |
| 254 | } |
| 255 | |
| 256 | // Setup handler for SIGPROF interrupts |
| 257 | EnableHandler(); |
| 258 | |
| 259 | return true; |
| 260 | } |
| 261 | |
| 262 | CpuProfiler::~CpuProfiler() { |
| 263 | Stop(); |
| 264 | } |
| 265 | |
| 266 | // Stop profiling and write out any collected profile data |
| 267 | void CpuProfiler::Stop() { |
| 268 | SpinLockHolder cl(&lock_); |
| 269 | |
| 270 | if (!collector_.enabled()) { |
| 271 | return; |
| 272 | } |
| 273 | |
| 274 | // Unregister prof_handler to stop receiving SIGPROF interrupts before |
| 275 | // stopping the collector. |
| 276 | DisableHandler(); |
| 277 | |
| 278 | // DisableHandler waits for the currently running callback to complete and |
| 279 | // guarantees no future invocations. It is safe to stop the collector. |
| 280 | collector_.Stop(); |
| 281 | } |
| 282 | |
| 283 | void CpuProfiler::FlushTable() { |
| 284 | SpinLockHolder cl(&lock_); |
| 285 | |
| 286 | if (!collector_.enabled()) { |
| 287 | return; |
| 288 | } |
| 289 | |
| 290 | // Unregister prof_handler to stop receiving SIGPROF interrupts before |
| 291 | // flushing the profile data. |
| 292 | DisableHandler(); |
| 293 | |
| 294 | // DisableHandler waits for the currently running callback to complete and |
| 295 | // guarantees no future invocations. It is safe to flush the profile data. |
| 296 | collector_.FlushTable(); |
| 297 | |
| 298 | EnableHandler(); |
| 299 | } |
| 300 | |
| 301 | bool CpuProfiler::Enabled() { |
| 302 | SpinLockHolder cl(&lock_); |
| 303 | return collector_.enabled(); |
| 304 | } |
| 305 | |
| 306 | void CpuProfiler::GetCurrentState(ProfilerState* state) { |
| 307 | ProfileData::State collector_state; |
| 308 | { |
| 309 | SpinLockHolder cl(&lock_); |
| 310 | collector_.GetCurrentState(&collector_state); |
| 311 | } |
| 312 | |
| 313 | state->enabled = collector_state.enabled; |
| 314 | state->start_time = static_cast<time_t>(collector_state.start_time); |
| 315 | state->samples_gathered = collector_state.samples_gathered; |
| 316 | int buf_size = sizeof(state->profile_name); |
| 317 | strncpy(state->profile_name, collector_state.profile_name, buf_size); |
| 318 | state->profile_name[buf_size-1] = '\0'; |
| 319 | } |
| 320 | |
| 321 | void CpuProfiler::EnableHandler() { |
| 322 | RAW_CHECK(prof_handler_token_ == NULL, "SIGPROF handler already registered"); |
| 323 | prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this); |
| 324 | RAW_CHECK(prof_handler_token_ != NULL, "Failed to set up SIGPROF handler"); |
| 325 | } |
| 326 | |
| 327 | void CpuProfiler::DisableHandler() { |
| 328 | RAW_CHECK(prof_handler_token_ != NULL, "SIGPROF handler is not registered"); |
| 329 | ProfileHandlerUnregisterCallback(prof_handler_token_); |
| 330 | prof_handler_token_ = NULL; |
| 331 | } |
| 332 | |
| 333 | // Signal handler that records the pc in the profile-data structure. We do no |
| 334 | // synchronization here. profile-handler.cc guarantees that at most one |
| 335 | // instance of prof_handler() will run at a time. All other routines that |
| 336 | // access the data touched by prof_handler() disable this signal handler before |
| 337 | // accessing the data and therefore cannot execute concurrently with |
| 338 | // prof_handler(). |
| 339 | void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext, |
| 340 | void* cpu_profiler) { |
| 341 | CpuProfiler* instance = static_cast<CpuProfiler*>(cpu_profiler); |
| 342 | |
| 343 | if (instance->filter_ == NULL || |
| 344 | (*instance->filter_)(instance->filter_arg_)) { |
| 345 | void* stack[ProfileData::kMaxStackDepth]; |
| 346 | |
| 347 | // Under frame-pointer-based unwinding at least on x86, the |
| 348 | // top-most active routine doesn't show up as a normal frame, but |
| 349 | // as the "pc" value in the signal handler context. |
| 350 | stack[0] = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext)); |
| 351 | |
| 352 | // We skip the top three stack trace entries (this function, |
| 353 | // SignalHandler::SignalHandler and one signal handler frame) |
| 354 | // since they are artifacts of profiling and should not be |
| 355 | // measured. Other profiling related frames may be removed by |
| 356 | // "pprof" at analysis time. Instead of skipping the top frames, |
| 357 | // we could skip nothing, but that would increase the profile size |
| 358 | // unnecessarily. |
| 359 | int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1, |
| 360 | 3, signal_ucontext); |
| 361 | |
| 362 | void **used_stack; |
| 363 | if (stack[1] == stack[0]) { |
| 364 | // in case of non-frame-pointer-based unwinding we will get |
| 365 | // duplicate of PC in stack[1], which we don't want |
| 366 | used_stack = stack + 1; |
| 367 | } else { |
| 368 | used_stack = stack; |
| 369 | depth++; // To account for pc value in stack[0]; |
| 370 | } |
| 371 | |
| 372 | instance->collector_.Add(depth, used_stack); |
| 373 | } |
| 374 | } |
| 375 | |
| 376 | #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) |
| 377 | |
| 378 | extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() { |
| 379 | ProfileHandlerRegisterThread(); |
| 380 | } |
| 381 | |
| 382 | extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() { |
| 383 | CpuProfiler::instance_.FlushTable(); |
| 384 | } |
| 385 | |
| 386 | extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() { |
| 387 | return CpuProfiler::instance_.Enabled(); |
| 388 | } |
| 389 | |
| 390 | extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) { |
| 391 | return CpuProfiler::instance_.Start(fname, NULL); |
| 392 | } |
| 393 | |
| 394 | extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions( |
| 395 | const char *fname, const ProfilerOptions *options) { |
| 396 | return CpuProfiler::instance_.Start(fname, options); |
| 397 | } |
| 398 | |
| 399 | extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() { |
| 400 | CpuProfiler::instance_.Stop(); |
| 401 | } |
| 402 | |
| 403 | extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState( |
| 404 | ProfilerState* state) { |
| 405 | CpuProfiler::instance_.GetCurrentState(state); |
| 406 | } |
| 407 | |
| 408 | #else // OS_CYGWIN |
| 409 | |
| 410 | // ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't |
| 411 | // work as well for profiling, and also interferes with alarm(). Because of |
| 412 | // these issues, unless a specific need is identified, profiler support is |
| 413 | // disabled under Cygwin. |
| 414 | extern "C" void ProfilerRegisterThread() { } |
| 415 | extern "C" void ProfilerFlush() { } |
| 416 | extern "C" int ProfilingIsEnabledForAllThreads() { return 0; } |
| 417 | extern "C" int ProfilerStart(const char* fname) { return 0; } |
| 418 | extern "C" int ProfilerStartWithOptions(const char *fname, |
| 419 | const ProfilerOptions *options) { |
| 420 | return 0; |
| 421 | } |
| 422 | extern "C" void ProfilerStop() { } |
| 423 | extern "C" void ProfilerGetCurrentState(ProfilerState* state) { |
| 424 | memset(state, 0, sizeof(*state)); |
| 425 | } |
| 426 | |
| 427 | #endif // OS_CYGWIN |
| 428 | |
| 429 | // DEPRECATED routines |
| 430 | extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { } |
| 431 | extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { } |