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