| 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 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 // | 82 // |
| 83 // Prior to determining whether timers are shared, this function will | 83 // Prior to determining whether timers are shared, this function will |
| 84 // unconditionally start the timer. However, if this function determines | 84 // unconditionally start the timer. However, if this function determines |
| 85 // that timers are shared, then it will stop the timer if no callbacks are | 85 // that timers are shared, then it will stop the timer if no callbacks are |
| 86 // currently registered. | 86 // currently registered. |
| 87 void RegisterThread(); | 87 void RegisterThread(); |
| 88 | 88 |
| 89 // Registers a callback routine to receive profile timer ticks. The returned | 89 // Registers a callback routine to receive profile timer ticks. The returned |
| 90 // token is to be used when unregistering this callback and must not be | 90 // token is to be used when unregistering this callback and must not be |
| 91 // deleted by the caller. Registration of the first callback enables the | 91 // deleted by the caller. Registration of the first callback enables the |
| 92 // SIGPROF handler. | 92 // SIGPROF handler (or SIGALRM if using ITIMER_REAL). |
| 93 ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback, | 93 ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback, |
| 94 void* callback_arg); | 94 void* callback_arg); |
| 95 | 95 |
| 96 // Unregisters a previously registered callback. Expects the token returned | 96 // Unregisters a previously registered callback. Expects the token returned |
| 97 // by the corresponding RegisterCallback routine. Unregistering the last | 97 // by the corresponding RegisterCallback routine. Unregistering the last |
| 98 // callback disables the SIGPROF handler. | 98 // callback disables the SIGPROF handler (or SIGALRM if using ITIMER_REAL). |
| 99 void UnregisterCallback(ProfileHandlerToken* token) | 99 void UnregisterCallback(ProfileHandlerToken* token) |
| 100 NO_THREAD_SAFETY_ANALYSIS; | 100 NO_THREAD_SAFETY_ANALYSIS; |
| 101 | 101 |
| 102 // Unregisters all the callbacks, stops the timer if shared, disables the | 102 // Unregisters all the callbacks, stops the timer if shared, disables the |
| 103 // SIGPROF handler and clears the timer_sharing_ state. | 103 // SIGPROF (or SIGALRM) handler and clears the timer_sharing_ state. |
| 104 void Reset(); | 104 void Reset(); |
| 105 | 105 |
| 106 // Gets the current state of profile handler. | 106 // Gets the current state of profile handler. |
| 107 void GetState(ProfileHandlerState* state); | 107 void GetState(ProfileHandlerState* state); |
| 108 | 108 |
| 109 // Initializes and returns the ProfileHandler singleton. | 109 // Initializes and returns the ProfileHandler singleton. |
| 110 static ProfileHandler* Instance(); | 110 static ProfileHandler* Instance(); |
| 111 | 111 |
| 112 private: | 112 private: |
| 113 ProfileHandler(); | 113 ProfileHandler(); |
| 114 ~ProfileHandler(); | 114 ~ProfileHandler(); |
| 115 | 115 |
| 116 // Largest allowed frequency. | 116 // Largest allowed frequency. |
| 117 static const int32 kMaxFrequency = 4000; | 117 static const int32 kMaxFrequency = 4000; |
| 118 // Default frequency. | 118 // Default frequency. |
| 119 static const int32 kDefaultFrequency = 100; | 119 static const int32 kDefaultFrequency = 100; |
| 120 | 120 |
| 121 // ProfileHandler singleton. | 121 // ProfileHandler singleton. |
| 122 static ProfileHandler* instance_; | 122 static ProfileHandler* instance_; |
| 123 | 123 |
| 124 // pthread_once_t for one time initialization of ProfileHandler singleton. | 124 // pthread_once_t for one time initialization of ProfileHandler singleton. |
| 125 static pthread_once_t once_; | 125 static pthread_once_t once_; |
| 126 | 126 |
| 127 // Initializes the ProfileHandler singleton via GoogleOnceInit. | 127 // Initializes the ProfileHandler singleton via GoogleOnceInit. |
| 128 static void Init(); | 128 static void Init(); |
| 129 | 129 |
| 130 // Counts the number of SIGPROF interrupts received. | 130 // The number of SIGPROF (or SIGALRM for ITIMER_REAL) interrupts received. |
| 131 int64 interrupts_ GUARDED_BY(signal_lock_); | 131 int64 interrupts_ GUARDED_BY(signal_lock_); |
| 132 | 132 |
| 133 // SIGPROF interrupt frequency, read-only after construction. | 133 // SIGPROF/SIGALRM interrupt frequency, read-only after construction. |
| 134 int32 frequency_; | 134 int32 frequency_; |
| 135 | 135 |
| 136 // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM) |
| 137 int timer_type_; |
| 138 |
| 136 // Counts the number of callbacks registered. | 139 // Counts the number of callbacks registered. |
| 137 int32 callback_count_ GUARDED_BY(control_lock_); | 140 int32 callback_count_ GUARDED_BY(control_lock_); |
| 138 | 141 |
| 139 // Whether or not the threading system provides interval timers that are | 142 // Whether or not the threading system provides interval timers that are |
| 140 // shared by all threads in a process. | 143 // shared by all threads in a process. |
| 141 enum { | 144 enum { |
| 142 // No timer initialization attempted yet. | 145 // No timer initialization attempted yet. |
| 143 TIMERS_UNTOUCHED, | 146 TIMERS_UNTOUCHED, |
| 144 // First thread has registered and set timer. | 147 // First thread has registered and set timer. |
| 145 TIMERS_ONE_SET, | 148 TIMERS_ONE_SET, |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 // 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 |
| 190 // used to detect whether timers are shared or separate.) | 193 // used to detect whether timers are shared or separate.) |
| 191 bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | 194 bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); |
| 192 | 195 |
| 193 // Sets the timer interrupt signal handler. | 196 // Sets the timer interrupt signal handler. |
| 194 void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | 197 void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); |
| 195 | 198 |
| 196 // Disables (ignores) the timer interrupt signal. | 199 // Disables (ignores) the timer interrupt signal. |
| 197 void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | 200 void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); |
| 198 | 201 |
| 199 // SIGPROF handler. Iterate over and call all the registered callbacks. | 202 // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks
. |
| 200 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); | 203 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); |
| 201 | 204 |
| 202 DISALLOW_EVIL_CONSTRUCTORS(ProfileHandler); | 205 DISALLOW_COPY_AND_ASSIGN(ProfileHandler); |
| 203 }; | 206 }; |
| 204 | 207 |
| 205 ProfileHandler* ProfileHandler::instance_ = NULL; | 208 ProfileHandler* ProfileHandler::instance_ = NULL; |
| 206 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; | 209 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; |
| 207 | 210 |
| 208 const int32 ProfileHandler::kMaxFrequency; | 211 const int32 ProfileHandler::kMaxFrequency; |
| 209 const int32 ProfileHandler::kDefaultFrequency; | 212 const int32 ProfileHandler::kDefaultFrequency; |
| 210 | 213 |
| 211 // If we are LD_PRELOAD-ed against a non-pthreads app, then | 214 // If we are LD_PRELOAD-ed against a non-pthreads app, then |
| 212 // pthread_once won't be defined. We declare it here, for that | 215 // pthread_once won't be defined. We declare it here, for that |
| (...skipping 21 matching lines...) Expand all Loading... |
| 234 assert(instance_ != NULL); | 237 assert(instance_ != NULL); |
| 235 } | 238 } |
| 236 return instance_; | 239 return instance_; |
| 237 } | 240 } |
| 238 | 241 |
| 239 ProfileHandler::ProfileHandler() | 242 ProfileHandler::ProfileHandler() |
| 240 : interrupts_(0), | 243 : interrupts_(0), |
| 241 callback_count_(0), | 244 callback_count_(0), |
| 242 timer_sharing_(TIMERS_UNTOUCHED) { | 245 timer_sharing_(TIMERS_UNTOUCHED) { |
| 243 SpinLockHolder cl(&control_lock_); | 246 SpinLockHolder cl(&control_lock_); |
| 247 |
| 248 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); |
| 249 |
| 244 // Get frequency of interrupts (if specified) | 250 // Get frequency of interrupts (if specified) |
| 245 char junk; | 251 char junk; |
| 246 const char* fr = getenv("CPUPROFILE_FREQUENCY"); | 252 const char* fr = getenv("CPUPROFILE_FREQUENCY"); |
| 247 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) && | 253 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) && |
| 248 (frequency_ > 0)) { | 254 (frequency_ > 0)) { |
| 249 // Limit to kMaxFrequency | 255 // Limit to kMaxFrequency |
| 250 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_; | 256 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_; |
| 251 } else { | 257 } else { |
| 252 frequency_ = kDefaultFrequency; | 258 frequency_ = kDefaultFrequency; |
| 253 } | 259 } |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 } | 389 } |
| 384 state->frequency = frequency_; | 390 state->frequency = frequency_; |
| 385 state->callback_count = callback_count_; | 391 state->callback_count = callback_count_; |
| 386 } | 392 } |
| 387 | 393 |
| 388 void ProfileHandler::StartTimer() { | 394 void ProfileHandler::StartTimer() { |
| 389 struct itimerval timer; | 395 struct itimerval timer; |
| 390 timer.it_interval.tv_sec = 0; | 396 timer.it_interval.tv_sec = 0; |
| 391 timer.it_interval.tv_usec = 1000000 / frequency_; | 397 timer.it_interval.tv_usec = 1000000 / frequency_; |
| 392 timer.it_value = timer.it_interval; | 398 timer.it_value = timer.it_interval; |
| 393 setitimer(ITIMER_PROF, &timer, 0); | 399 setitimer(timer_type_, &timer, 0); |
| 394 } | 400 } |
| 395 | 401 |
| 396 void ProfileHandler::StopTimer() { | 402 void ProfileHandler::StopTimer() { |
| 397 struct itimerval timer; | 403 struct itimerval timer; |
| 398 memset(&timer, 0, sizeof timer); | 404 memset(&timer, 0, sizeof timer); |
| 399 setitimer(ITIMER_PROF, &timer, 0); | 405 setitimer(timer_type_, &timer, 0); |
| 400 } | 406 } |
| 401 | 407 |
| 402 bool ProfileHandler::IsTimerRunning() { | 408 bool ProfileHandler::IsTimerRunning() { |
| 403 struct itimerval current_timer; | 409 struct itimerval current_timer; |
| 404 RAW_CHECK(0 == getitimer(ITIMER_PROF, ¤t_timer), "getitimer"); | 410 RAW_CHECK(0 == getitimer(timer_type_, ¤t_timer), "getitimer"); |
| 405 return (current_timer.it_value.tv_sec != 0 || | 411 return (current_timer.it_value.tv_sec != 0 || |
| 406 current_timer.it_value.tv_usec != 0); | 412 current_timer.it_value.tv_usec != 0); |
| 407 } | 413 } |
| 408 | 414 |
| 409 void ProfileHandler::EnableHandler() { | 415 void ProfileHandler::EnableHandler() { |
| 410 struct sigaction sa; | 416 struct sigaction sa; |
| 411 sa.sa_sigaction = SignalHandler; | 417 sa.sa_sigaction = SignalHandler; |
| 412 sa.sa_flags = SA_RESTART | SA_SIGINFO; | 418 sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| 413 sigemptyset(&sa.sa_mask); | 419 sigemptyset(&sa.sa_mask); |
| 414 RAW_CHECK(sigaction(SIGPROF, &sa, NULL) == 0, "sigprof (enable)"); | 420 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); |
| 421 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (enable)"); |
| 415 } | 422 } |
| 416 | 423 |
| 417 void ProfileHandler::DisableHandler() { | 424 void ProfileHandler::DisableHandler() { |
| 418 struct sigaction sa; | 425 struct sigaction sa; |
| 419 sa.sa_handler = SIG_IGN; | 426 sa.sa_handler = SIG_IGN; |
| 420 sa.sa_flags = SA_RESTART; | 427 sa.sa_flags = SA_RESTART; |
| 421 sigemptyset(&sa.sa_mask); | 428 sigemptyset(&sa.sa_mask); |
| 422 RAW_CHECK(sigaction(SIGPROF, &sa, NULL) == 0, "sigprof (disable)"); | 429 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); |
| 430 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)"); |
| 423 } | 431 } |
| 424 | 432 |
| 425 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { | 433 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { |
| 426 int saved_errno = errno; | 434 int saved_errno = errno; |
| 427 RAW_CHECK(instance_ != NULL, "ProfileHandler is not initialized"); | 435 RAW_CHECK(instance_ != NULL, "ProfileHandler is not initialized"); |
| 428 { | 436 { |
| 429 SpinLockHolder sl(&instance_->signal_lock_); | 437 SpinLockHolder sl(&instance_->signal_lock_); |
| 430 ++instance_->interrupts_; | 438 ++instance_->interrupts_; |
| 431 for (CallbackIterator it = instance_->callbacks_.begin(); | 439 for (CallbackIterator it = instance_->callbacks_.begin(); |
| 432 it != instance_->callbacks_.end(); | 440 it != instance_->callbacks_.end(); |
| 433 ++it) { | 441 ++it) { |
| 434 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); | 442 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); |
| 435 } | 443 } |
| 436 } | 444 } |
| 437 errno = saved_errno; | 445 errno = saved_errno; |
| 438 } | 446 } |
| 439 | 447 |
| 440 // The sole purpose of this class is to initialize the ProfileHandler singleton | 448 // The sole purpose of this class is to initialize the ProfileHandler singleton |
| 441 // when the global static objects are created. Note that the main thread will | 449 // when the global static objects are created. Note that the main thread will |
| 442 // be registered at this time. | 450 // be registered at this time. |
| 443 class ProfileHandlerInitializer { | 451 class ProfileHandlerInitializer { |
| 444 public: | 452 public: |
| 445 ProfileHandlerInitializer() { | 453 ProfileHandlerInitializer() { |
| 446 ProfileHandler::Instance()->RegisterThread(); | 454 ProfileHandler::Instance()->RegisterThread(); |
| 447 } | 455 } |
| 448 | 456 |
| 449 private: | 457 private: |
| 450 DISALLOW_EVIL_CONSTRUCTORS(ProfileHandlerInitializer); | 458 DISALLOW_COPY_AND_ASSIGN(ProfileHandlerInitializer); |
| 451 }; | 459 }; |
| 452 // ProfileHandlerInitializer singleton | 460 // ProfileHandlerInitializer singleton |
| 453 static ProfileHandlerInitializer profile_handler_initializer; | 461 static ProfileHandlerInitializer profile_handler_initializer; |
| 454 | 462 |
| 455 extern "C" void ProfileHandlerRegisterThread() { | 463 extern "C" void ProfileHandlerRegisterThread() { |
| 456 ProfileHandler::Instance()->RegisterThread(); | 464 ProfileHandler::Instance()->RegisterThread(); |
| 457 } | 465 } |
| 458 | 466 |
| 459 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( | 467 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( |
| 460 ProfileHandlerCallback callback, void* callback_arg) { | 468 ProfileHandlerCallback callback, void* callback_arg) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 490 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { | 498 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { |
| 491 } | 499 } |
| 492 | 500 |
| 493 extern "C" void ProfileHandlerReset() { | 501 extern "C" void ProfileHandlerReset() { |
| 494 } | 502 } |
| 495 | 503 |
| 496 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { | 504 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { |
| 497 } | 505 } |
| 498 | 506 |
| 499 #endif // OS_CYGWIN | 507 #endif // OS_CYGWIN |
| OLD | NEW |