| OLD | NEW |
| 1 // Copyright (c) 2009, Google Inc. | 1 // Copyright (c) 2009, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) | 39 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) |
| 40 | 40 |
| 41 #include <stdio.h> | 41 #include <stdio.h> |
| 42 #include <errno.h> | 42 #include <errno.h> |
| 43 #include <sys/time.h> | 43 #include <sys/time.h> |
| 44 | 44 |
| 45 #include <list> | 45 #include <list> |
| 46 #include <string> | 46 #include <string> |
| 47 | 47 |
| 48 #include "base/dynamic_annotations.h" | 48 #include "base/dynamic_annotations.h" |
| 49 #include "base/googleinit.h" | |
| 50 #include "base/logging.h" | 49 #include "base/logging.h" |
| 51 #include "base/spinlock.h" | 50 #include "base/spinlock.h" |
| 52 #include "maybe_threads.h" | 51 #include "maybe_threads.h" |
| 53 | 52 |
| 54 using std::list; | 53 using std::list; |
| 55 using std::string; | 54 using std::string; |
| 56 | 55 |
| 57 // This structure is used by ProfileHandlerRegisterCallback and | 56 // This structure is used by ProfileHandlerRegisterCallback and |
| 58 // ProfileHandlerUnregisterCallback as a handle to a registered callback. | 57 // ProfileHandlerUnregisterCallback as a handle to a registered callback. |
| 59 struct ProfileHandlerToken { | 58 struct ProfileHandlerToken { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 | 132 |
| 134 // SIGPROF/SIGALRM interrupt frequency, read-only after construction. | 133 // SIGPROF/SIGALRM interrupt frequency, read-only after construction. |
| 135 int32 frequency_; | 134 int32 frequency_; |
| 136 | 135 |
| 137 // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM) | 136 // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM) |
| 138 int timer_type_; | 137 int timer_type_; |
| 139 | 138 |
| 140 // Counts the number of callbacks registered. | 139 // Counts the number of callbacks registered. |
| 141 int32 callback_count_ GUARDED_BY(control_lock_); | 140 int32 callback_count_ GUARDED_BY(control_lock_); |
| 142 | 141 |
| 143 // Is profiling allowed at all? | |
| 144 bool allowed_; | |
| 145 | |
| 146 // Whether or not the threading system provides interval timers that are | 142 // Whether or not the threading system provides interval timers that are |
| 147 // shared by all threads in a process. | 143 // shared by all threads in a process. |
| 148 enum { | 144 enum { |
| 149 // No timer initialization attempted yet. | 145 // No timer initialization attempted yet. |
| 150 TIMERS_UNTOUCHED, | 146 TIMERS_UNTOUCHED, |
| 151 // First thread has registered and set timer. | 147 // First thread has registered and set timer. |
| 152 TIMERS_ONE_SET, | 148 TIMERS_ONE_SET, |
| 153 // Timers are shared by all threads. | 149 // Timers are shared by all threads. |
| 154 TIMERS_SHARED, | 150 TIMERS_SHARED, |
| 155 // Timers are separate in each thread. | 151 // Timers are separate in each thread. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 // thread. This actually checks the kernel's interval timer setting. (It is | 192 // thread. This actually checks the kernel's interval timer setting. (It is |
| 197 // used to detect whether timers are shared or separate.) | 193 // used to detect whether timers are shared or separate.) |
| 198 bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | 194 bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); |
| 199 | 195 |
| 200 // Sets the timer interrupt signal handler. | 196 // Sets the timer interrupt signal handler. |
| 201 void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | 197 void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); |
| 202 | 198 |
| 203 // Disables (ignores) the timer interrupt signal. | 199 // Disables (ignores) the timer interrupt signal. |
| 204 void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | 200 void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); |
| 205 | 201 |
| 206 // Returns true if the handler is not being used by something else. | |
| 207 // This checks the kernel's signal handler table. | |
| 208 bool IsSignalHandlerAvailable(); | |
| 209 | |
| 210 // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks
. | 202 // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks
. |
| 211 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); | 203 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); |
| 212 | 204 |
| 213 DISALLOW_COPY_AND_ASSIGN(ProfileHandler); | 205 DISALLOW_COPY_AND_ASSIGN(ProfileHandler); |
| 214 }; | 206 }; |
| 215 | 207 |
| 216 ProfileHandler* ProfileHandler::instance_ = NULL; | 208 ProfileHandler* ProfileHandler::instance_ = NULL; |
| 217 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; | 209 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; |
| 218 | 210 |
| 219 const int32 ProfileHandler::kMaxFrequency; | 211 const int32 ProfileHandler::kMaxFrequency; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 240 // (but doesn't do anything) even when pthreads isn't linked in. | 232 // (but doesn't do anything) even when pthreads isn't linked in. |
| 241 Init(); | 233 Init(); |
| 242 assert(instance_ != NULL); | 234 assert(instance_ != NULL); |
| 243 } | 235 } |
| 244 return instance_; | 236 return instance_; |
| 245 } | 237 } |
| 246 | 238 |
| 247 ProfileHandler::ProfileHandler() | 239 ProfileHandler::ProfileHandler() |
| 248 : interrupts_(0), | 240 : interrupts_(0), |
| 249 callback_count_(0), | 241 callback_count_(0), |
| 250 allowed_(true), | |
| 251 timer_sharing_(TIMERS_UNTOUCHED) { | 242 timer_sharing_(TIMERS_UNTOUCHED) { |
| 252 SpinLockHolder cl(&control_lock_); | 243 SpinLockHolder cl(&control_lock_); |
| 253 | 244 |
| 254 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); | 245 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); |
| 255 | 246 |
| 256 // Get frequency of interrupts (if specified) | 247 // Get frequency of interrupts (if specified) |
| 257 char junk; | 248 char junk; |
| 258 const char* fr = getenv("CPUPROFILE_FREQUENCY"); | 249 const char* fr = getenv("CPUPROFILE_FREQUENCY"); |
| 259 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) && | 250 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) && |
| 260 (frequency_ > 0)) { | 251 (frequency_ > 0)) { |
| 261 // Limit to kMaxFrequency | 252 // Limit to kMaxFrequency |
| 262 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_; | 253 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_; |
| 263 } else { | 254 } else { |
| 264 frequency_ = kDefaultFrequency; | 255 frequency_ = kDefaultFrequency; |
| 265 } | 256 } |
| 266 | 257 |
| 267 if (!allowed_) { | |
| 268 return; | |
| 269 } | |
| 270 | |
| 271 // If something else is using the signal handler, | |
| 272 // assume it has priority over us and stop. | |
| 273 if (!IsSignalHandlerAvailable()) { | |
| 274 RAW_LOG(INFO, "Disabling profiler because %s handler is already in use.", | |
| 275 timer_type_ == ITIMER_REAL ? "SIGALRM" : "SIGPROF"); | |
| 276 allowed_ = false; | |
| 277 return; | |
| 278 } | |
| 279 | |
| 280 // Ignore signals until we decide to turn profiling on. (Paranoia; | 258 // Ignore signals until we decide to turn profiling on. (Paranoia; |
| 281 // should already be ignored.) | 259 // should already be ignored.) |
| 282 DisableHandler(); | 260 DisableHandler(); |
| 283 } | 261 } |
| 284 | 262 |
| 285 ProfileHandler::~ProfileHandler() { | 263 ProfileHandler::~ProfileHandler() { |
| 286 Reset(); | 264 Reset(); |
| 287 } | 265 } |
| 288 | 266 |
| 289 void ProfileHandler::RegisterThread() { | 267 void ProfileHandler::RegisterThread() { |
| 290 SpinLockHolder cl(&control_lock_); | 268 SpinLockHolder cl(&control_lock_); |
| 291 | 269 |
| 292 if (!allowed_) { | |
| 293 return; | |
| 294 } | |
| 295 | |
| 296 // We try to detect whether timers are being shared by setting a | 270 // We try to detect whether timers are being shared by setting a |
| 297 // timer in the first call to this function, then checking whether | 271 // timer in the first call to this function, then checking whether |
| 298 // it's set in the second call. | 272 // it's set in the second call. |
| 299 // | 273 // |
| 300 // Note that this detection method requires that the first two calls | 274 // Note that this detection method requires that the first two calls |
| 301 // to RegisterThread must be made from different threads. (Subsequent | 275 // to RegisterThread must be made from different threads. (Subsequent |
| 302 // calls will see timer_sharing_ set to either TIMERS_SEPARATE or | 276 // calls will see timer_sharing_ set to either TIMERS_SEPARATE or |
| 303 // TIMERS_SHARED, and won't try to detect the timer sharing type.) | 277 // TIMERS_SHARED, and won't try to detect the timer sharing type.) |
| 304 // | 278 // |
| 305 // Also note that if timer settings were inherited across new thread | 279 // Also note that if timer settings were inherited across new thread |
| (...skipping 25 matching lines...) Expand all Loading... |
| 331 // Nothing needed. | 305 // Nothing needed. |
| 332 break; | 306 break; |
| 333 case TIMERS_SEPARATE: | 307 case TIMERS_SEPARATE: |
| 334 StartTimer(); | 308 StartTimer(); |
| 335 break; | 309 break; |
| 336 } | 310 } |
| 337 } | 311 } |
| 338 | 312 |
| 339 ProfileHandlerToken* ProfileHandler::RegisterCallback( | 313 ProfileHandlerToken* ProfileHandler::RegisterCallback( |
| 340 ProfileHandlerCallback callback, void* callback_arg) { | 314 ProfileHandlerCallback callback, void* callback_arg) { |
| 341 | |
| 342 ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg); | 315 ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg); |
| 343 | 316 |
| 344 SpinLockHolder cl(&control_lock_); | 317 SpinLockHolder cl(&control_lock_); |
| 345 DisableHandler(); | 318 DisableHandler(); |
| 346 { | 319 { |
| 347 SpinLockHolder sl(&signal_lock_); | 320 SpinLockHolder sl(&signal_lock_); |
| 348 callbacks_.push_back(token); | 321 callbacks_.push_back(token); |
| 349 } | 322 } |
| 350 // Start the timer if timer is shared and this is a first callback. | 323 // Start the timer if timer is shared and this is a first callback. |
| 351 if ((callback_count_ == 0) && (timer_sharing_ == TIMERS_SHARED)) { | 324 if ((callback_count_ == 0) && (timer_sharing_ == TIMERS_SHARED)) { |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 DisableHandler(); | 379 DisableHandler(); |
| 407 { | 380 { |
| 408 SpinLockHolder sl(&signal_lock_); // Protects interrupts_. | 381 SpinLockHolder sl(&signal_lock_); // Protects interrupts_. |
| 409 state->interrupts = interrupts_; | 382 state->interrupts = interrupts_; |
| 410 } | 383 } |
| 411 if (callback_count_ > 0) { | 384 if (callback_count_ > 0) { |
| 412 EnableHandler(); | 385 EnableHandler(); |
| 413 } | 386 } |
| 414 state->frequency = frequency_; | 387 state->frequency = frequency_; |
| 415 state->callback_count = callback_count_; | 388 state->callback_count = callback_count_; |
| 416 state->allowed = allowed_; | |
| 417 } | 389 } |
| 418 | 390 |
| 419 void ProfileHandler::StartTimer() { | 391 void ProfileHandler::StartTimer() { |
| 420 if (!allowed_) { | |
| 421 return; | |
| 422 } | |
| 423 struct itimerval timer; | 392 struct itimerval timer; |
| 424 timer.it_interval.tv_sec = 0; | 393 timer.it_interval.tv_sec = 0; |
| 425 timer.it_interval.tv_usec = 1000000 / frequency_; | 394 timer.it_interval.tv_usec = 1000000 / frequency_; |
| 426 timer.it_value = timer.it_interval; | 395 timer.it_value = timer.it_interval; |
| 427 setitimer(timer_type_, &timer, 0); | 396 setitimer(timer_type_, &timer, 0); |
| 428 } | 397 } |
| 429 | 398 |
| 430 void ProfileHandler::StopTimer() { | 399 void ProfileHandler::StopTimer() { |
| 431 if (!allowed_) { | |
| 432 return; | |
| 433 } | |
| 434 struct itimerval timer; | 400 struct itimerval timer; |
| 435 memset(&timer, 0, sizeof timer); | 401 memset(&timer, 0, sizeof timer); |
| 436 setitimer(timer_type_, &timer, 0); | 402 setitimer(timer_type_, &timer, 0); |
| 437 } | 403 } |
| 438 | 404 |
| 439 bool ProfileHandler::IsTimerRunning() { | 405 bool ProfileHandler::IsTimerRunning() { |
| 440 if (!allowed_) { | |
| 441 return false; | |
| 442 } | |
| 443 struct itimerval current_timer; | 406 struct itimerval current_timer; |
| 444 RAW_CHECK(0 == getitimer(timer_type_, ¤t_timer), "getitimer"); | 407 RAW_CHECK(0 == getitimer(timer_type_, ¤t_timer), "getitimer"); |
| 445 return (current_timer.it_value.tv_sec != 0 || | 408 return (current_timer.it_value.tv_sec != 0 || |
| 446 current_timer.it_value.tv_usec != 0); | 409 current_timer.it_value.tv_usec != 0); |
| 447 } | 410 } |
| 448 | 411 |
| 449 void ProfileHandler::EnableHandler() { | 412 void ProfileHandler::EnableHandler() { |
| 450 if (!allowed_) { | |
| 451 return; | |
| 452 } | |
| 453 struct sigaction sa; | 413 struct sigaction sa; |
| 454 sa.sa_sigaction = SignalHandler; | 414 sa.sa_sigaction = SignalHandler; |
| 455 sa.sa_flags = SA_RESTART | SA_SIGINFO; | 415 sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| 456 sigemptyset(&sa.sa_mask); | 416 sigemptyset(&sa.sa_mask); |
| 457 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); | 417 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); |
| 458 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (enable)"); | 418 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (enable)"); |
| 459 } | 419 } |
| 460 | 420 |
| 461 void ProfileHandler::DisableHandler() { | 421 void ProfileHandler::DisableHandler() { |
| 462 if (!allowed_) { | |
| 463 return; | |
| 464 } | |
| 465 struct sigaction sa; | 422 struct sigaction sa; |
| 466 sa.sa_handler = SIG_IGN; | 423 sa.sa_handler = SIG_IGN; |
| 467 sa.sa_flags = SA_RESTART; | 424 sa.sa_flags = SA_RESTART; |
| 468 sigemptyset(&sa.sa_mask); | 425 sigemptyset(&sa.sa_mask); |
| 469 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); | 426 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); |
| 470 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)"); | 427 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)"); |
| 471 } | 428 } |
| 472 | 429 |
| 473 bool ProfileHandler::IsSignalHandlerAvailable() { | |
| 474 struct sigaction sa; | |
| 475 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); | |
| 476 RAW_CHECK(sigaction(signal_number, NULL, &sa) == 0, "is-signal-handler avail")
; | |
| 477 | |
| 478 // We only take over the handler if the current one is unset. | |
| 479 // It must be SIG_IGN or SIG_DFL, not some other function. | |
| 480 // SIG_IGN must be allowed because when profiling is allowed but | |
| 481 // not actively in use, this code keeps the handler set to SIG_IGN. | |
| 482 // That setting will be inherited across fork+exec. In order for | |
| 483 // any child to be able to use profiling, SIG_IGN must be treated | |
| 484 // as available. | |
| 485 return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL; | |
| 486 } | |
| 487 | |
| 488 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { | 430 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { |
| 489 int saved_errno = errno; | 431 int saved_errno = errno; |
| 490 // At this moment, instance_ must be initialized because the handler is | 432 RAW_CHECK(instance_ != NULL, "ProfileHandler is not initialized"); |
| 491 // enabled in RegisterThread or RegisterCallback only after | |
| 492 // ProfileHandler::Instance runs. | |
| 493 ProfileHandler* instance = ANNOTATE_UNPROTECTED_READ(instance_); | |
| 494 RAW_CHECK(instance != NULL, "ProfileHandler is not initialized"); | |
| 495 { | 433 { |
| 496 SpinLockHolder sl(&instance->signal_lock_); | 434 SpinLockHolder sl(&instance_->signal_lock_); |
| 497 ++instance->interrupts_; | 435 ++instance_->interrupts_; |
| 498 for (CallbackIterator it = instance->callbacks_.begin(); | 436 for (CallbackIterator it = instance_->callbacks_.begin(); |
| 499 it != instance->callbacks_.end(); | 437 it != instance_->callbacks_.end(); |
| 500 ++it) { | 438 ++it) { |
| 501 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); | 439 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); |
| 502 } | 440 } |
| 503 } | 441 } |
| 504 errno = saved_errno; | 442 errno = saved_errno; |
| 505 } | 443 } |
| 506 | 444 |
| 507 // This module initializer registers the main thread, so it must be | 445 // The sole purpose of this class is to initialize the ProfileHandler singleton |
| 508 // executed in the context of the main thread. | 446 // when the global static objects are created. Note that the main thread will |
| 509 REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread()); | 447 // be registered at this time. |
| 448 class ProfileHandlerInitializer { |
| 449 public: |
| 450 ProfileHandlerInitializer() { |
| 451 ProfileHandler::Instance()->RegisterThread(); |
| 452 } |
| 453 |
| 454 private: |
| 455 DISALLOW_COPY_AND_ASSIGN(ProfileHandlerInitializer); |
| 456 }; |
| 457 // ProfileHandlerInitializer singleton |
| 458 static ProfileHandlerInitializer profile_handler_initializer; |
| 510 | 459 |
| 511 extern "C" void ProfileHandlerRegisterThread() { | 460 extern "C" void ProfileHandlerRegisterThread() { |
| 512 ProfileHandler::Instance()->RegisterThread(); | 461 ProfileHandler::Instance()->RegisterThread(); |
| 513 } | 462 } |
| 514 | 463 |
| 515 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( | 464 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( |
| 516 ProfileHandlerCallback callback, void* callback_arg) { | 465 ProfileHandlerCallback callback, void* callback_arg) { |
| 517 return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg); | 466 return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg); |
| 518 } | 467 } |
| 519 | 468 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 546 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { | 495 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { |
| 547 } | 496 } |
| 548 | 497 |
| 549 extern "C" void ProfileHandlerReset() { | 498 extern "C" void ProfileHandlerReset() { |
| 550 } | 499 } |
| 551 | 500 |
| 552 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { | 501 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { |
| 553 } | 502 } |
| 554 | 503 |
| 555 #endif // OS_CYGWIN | 504 #endif // OS_CYGWIN |
| OLD | NEW |