Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | |
|
alph
2014/09/09 13:54:37
Please revert
| |
| 5 #include "src/sampler.h" | 4 #include "src/sampler.h" |
| 6 | 5 |
| 7 #if V8_OS_POSIX && !V8_OS_CYGWIN | 6 #if V8_OS_POSIX && !V8_OS_CYGWIN |
| 8 | 7 |
| 9 #define USE_SIGNALS | 8 #define USE_SIGNALS |
| 10 | 9 |
| 11 #include <errno.h> | 10 #include <errno.h> |
| 12 #include <pthread.h> | 11 #include <pthread.h> |
| 13 #include <signal.h> | 12 #include <signal.h> |
| 14 #include <sys/time.h> | 13 #include <sys/time.h> |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 37 #endif | 36 #endif |
| 38 | 37 |
| 39 #elif V8_OS_WIN || V8_OS_CYGWIN | 38 #elif V8_OS_WIN || V8_OS_CYGWIN |
| 40 | 39 |
| 41 #include "src/base/win32-headers.h" | 40 #include "src/base/win32-headers.h" |
| 42 | 41 |
| 43 #endif | 42 #endif |
| 44 | 43 |
| 45 #include "src/v8.h" | 44 #include "src/v8.h" |
| 46 | 45 |
| 46 #include "src/base/logging.h" | |
| 47 #include "src/base/platform/platform.h" | 47 #include "src/base/platform/platform.h" |
| 48 #include "src/cpu-profiler-inl.h" | 48 #include "src/cpu-profiler-inl.h" |
| 49 #include "src/flags.h" | 49 #include "src/flags.h" |
| 50 #include "src/frames-inl.h" | 50 #include "src/frames-inl.h" |
| 51 #include "src/log.h" | 51 #include "src/log.h" |
| 52 #include "src/simulator.h" | 52 #include "src/simulator.h" |
| 53 #include "src/v8threads.h" | 53 #include "src/v8threads.h" |
| 54 #include "src/vm-state-inl.h" | 54 #include "src/vm-state-inl.h" |
| 55 | 55 |
| 56 | 56 |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 268 private: | 268 private: |
| 269 Simulator* simulator_; | 269 Simulator* simulator_; |
| 270 }; | 270 }; |
| 271 #endif // USE_SIMULATOR | 271 #endif // USE_SIMULATOR |
| 272 | 272 |
| 273 | 273 |
| 274 #if defined(USE_SIGNALS) | 274 #if defined(USE_SIGNALS) |
| 275 | 275 |
| 276 class SignalHandler : public AllStatic { | 276 class SignalHandler : public AllStatic { |
| 277 public: | 277 public: |
| 278 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } | 278 static void SetUp() { |
| 279 static void TearDown() { delete mutex_; mutex_ = NULL; } | 279 CHECK_EQ(NULL, mutex_); |
| 280 CHECK_EQ(NULL, sampling_semaphore_); | |
| 281 | |
| 282 mutex_ = new base::Mutex(); | |
| 283 sampling_semaphore_ = new base::Semaphore(0); | |
| 284 } | |
| 285 | |
| 286 static void TearDown() { | |
| 287 delete mutex_; | |
| 288 delete sampling_semaphore_; | |
| 289 | |
| 290 mutex_ = NULL; | |
| 291 sampling_semaphore_ = NULL; | |
| 292 } | |
| 280 | 293 |
| 281 static void IncreaseSamplerCount() { | 294 static void IncreaseSamplerCount() { |
| 282 base::LockGuard<base::Mutex> lock_guard(mutex_); | 295 base::LockGuard<base::Mutex> lock_guard(mutex_); |
| 283 if (++client_count_ == 1) Install(); | 296 if (++client_count_ == 1) Install(); |
| 284 } | 297 } |
| 285 | 298 |
| 286 static void DecreaseSamplerCount() { | 299 static void DecreaseSamplerCount() { |
| 287 base::LockGuard<base::Mutex> lock_guard(mutex_); | 300 base::LockGuard<base::Mutex> lock_guard(mutex_); |
| 288 if (--client_count_ == 0) Restore(); | 301 if (--client_count_ == 0) Restore(); |
| 289 } | 302 } |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 313 if (signal_handler_installed_) { | 326 if (signal_handler_installed_) { |
| 314 sigaction(SIGPROF, &old_signal_handler_, 0); | 327 sigaction(SIGPROF, &old_signal_handler_, 0); |
| 315 signal_handler_installed_ = false; | 328 signal_handler_installed_ = false; |
| 316 } | 329 } |
| 317 #endif | 330 #endif |
| 318 } | 331 } |
| 319 | 332 |
| 320 #if !V8_OS_NACL | 333 #if !V8_OS_NACL |
| 321 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); | 334 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); |
| 322 #endif | 335 #endif |
| 336 | |
| 337 // The SIGPROF could have come from DoSample or from GetSample. | |
| 338 // GetSample is the internal endpoint for the public | |
| 339 // GetSample API, which aims to bypass all the internal buffers | |
| 340 // and return just one sample instead, rightaway. | |
| 341 // TODO(gholap): Eventually, get rid of DoSample. | |
| 342 // Only GetSample should remain. | |
| 343 | |
| 344 // This is the sample which will be filled by the call from GetSample. | |
| 345 static TickSample sample_; | |
| 346 | |
| 347 // For the SIGPROF handler to know whether the call was from GetSample. | |
| 348 static volatile bool called_from_get_sample_; | |
| 349 | |
| 350 // GetSample waits synchronously till the SIGPROF handler returns. | |
| 351 // this semaphore is used to signal GetSample. | |
| 352 static base::Semaphore* sampling_semaphore_; | |
| 353 | |
| 354 // It is not that every time HandleProfilerSignal is invoked, | |
| 355 // it succeeds in obtaining a sample. | |
| 356 // This provides GetSample with the information whether | |
| 357 // the handler finished with or without getting the sample. | |
| 358 static bool sample_available_; | |
| 359 | |
| 323 // Protects the process wide state below. | 360 // Protects the process wide state below. |
| 324 static base::Mutex* mutex_; | 361 static base::Mutex* mutex_; |
| 325 static int client_count_; | 362 static int client_count_; |
| 326 static bool signal_handler_installed_; | 363 static bool signal_handler_installed_; |
| 327 static struct sigaction old_signal_handler_; | 364 static struct sigaction old_signal_handler_; |
| 365 | |
| 366 friend class Sampler; | |
| 328 }; | 367 }; |
| 329 | 368 |
| 330 | 369 |
| 370 TickSample SignalHandler::sample_; | |
| 371 volatile bool SignalHandler::called_from_get_sample_ = false; | |
| 372 base::Semaphore* SignalHandler::sampling_semaphore_ = NULL; | |
| 373 bool SignalHandler::sample_available_ = false; | |
| 374 | |
| 331 base::Mutex* SignalHandler::mutex_ = NULL; | 375 base::Mutex* SignalHandler::mutex_ = NULL; |
| 332 int SignalHandler::client_count_ = 0; | 376 int SignalHandler::client_count_ = 0; |
| 333 struct sigaction SignalHandler::old_signal_handler_; | 377 struct sigaction SignalHandler::old_signal_handler_; |
| 334 bool SignalHandler::signal_handler_installed_ = false; | 378 bool SignalHandler::signal_handler_installed_ = false; |
| 335 | 379 |
| 336 | 380 |
| 337 // As Native Client does not support signal handling, profiling is disabled. | 381 // As Native Client does not support signal handling, profiling is disabled. |
| 338 #if !V8_OS_NACL | 382 #if !V8_OS_NACL |
| 339 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, | 383 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, |
| 340 void* context) { | 384 void* context) { |
| 385 // Even if we return prematurely, | |
| 386 // we need to signal the sampling_semaphore_ | |
| 387 sample_available_ = false; | |
| 388 ScopedSemaphore scoped_semaphore(sampling_semaphore_); | |
| 389 | |
| 341 USE(info); | 390 USE(info); |
| 342 if (signal != SIGPROF) return; | 391 if (signal != SIGPROF) return; |
| 343 Isolate* isolate = Isolate::UnsafeCurrent(); | 392 Isolate* isolate = Isolate::UnsafeCurrent(); |
| 344 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { | 393 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { |
| 345 // We require a fully initialized and entered isolate. | 394 // We require a fully initialized and entered isolate. |
| 346 return; | 395 return; |
| 347 } | 396 } |
| 348 if (v8::Locker::IsActive() && | 397 if (v8::Locker::IsActive() && |
| 349 !isolate->thread_manager()->IsLockedByCurrentThread()) { | 398 !isolate->thread_manager()->IsLockedByCurrentThread()) { |
| 350 return; | 399 return; |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 472 state.pc = reinterpret_cast<Address>(mcontext.cpu.eip); | 521 state.pc = reinterpret_cast<Address>(mcontext.cpu.eip); |
| 473 state.sp = reinterpret_cast<Address>(mcontext.cpu.esp); | 522 state.sp = reinterpret_cast<Address>(mcontext.cpu.esp); |
| 474 state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp); | 523 state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp); |
| 475 #elif V8_HOST_ARCH_ARM | 524 #elif V8_HOST_ARCH_ARM |
| 476 state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]); | 525 state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]); |
| 477 state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]); | 526 state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]); |
| 478 state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]); | 527 state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]); |
| 479 #endif // V8_HOST_ARCH_* | 528 #endif // V8_HOST_ARCH_* |
| 480 #endif // V8_OS_QNX | 529 #endif // V8_OS_QNX |
| 481 #endif // USE_SIMULATOR | 530 #endif // USE_SIMULATOR |
| 482 sampler->SampleStack(state); | 531 if (called_from_get_sample_) { |
| 532 sample_.Init(sampler->isolate(), state); | |
| 533 } else { | |
| 534 sampler->SampleStack(state); | |
| 535 } | |
| 536 sample_available_ = true; | |
| 483 } | 537 } |
| 484 #endif // V8_OS_NACL | 538 #endif // V8_OS_NACL |
| 485 | 539 |
| 486 #endif | 540 #endif |
| 487 | 541 |
| 488 | 542 |
| 489 class SamplerThread : public base::Thread { | 543 class SamplerThread : public base::Thread { |
| 490 public: | 544 public: |
| 491 static const int kSamplerThreadStackSize = 64 * KB; | 545 static const int kSamplerThreadStackSize = 64 * KB; |
| 492 | 546 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 575 | 629 |
| 576 // | 630 // |
| 577 // StackTracer implementation | 631 // StackTracer implementation |
| 578 // | 632 // |
| 579 DISABLE_ASAN void TickSample::Init(Isolate* isolate, | 633 DISABLE_ASAN void TickSample::Init(Isolate* isolate, |
| 580 const RegisterState& regs) { | 634 const RegisterState& regs) { |
| 581 DCHECK(isolate->IsInitialized()); | 635 DCHECK(isolate->IsInitialized()); |
| 582 timestamp = base::TimeTicks::HighResolutionNow(); | 636 timestamp = base::TimeTicks::HighResolutionNow(); |
| 583 pc = regs.pc; | 637 pc = regs.pc; |
| 584 state = isolate->current_vm_state(); | 638 state = isolate->current_vm_state(); |
| 639 frames_count = 0; | |
| 585 | 640 |
| 586 // Avoid collecting traces while doing GC. | 641 // Avoid collecting traces while doing GC. |
| 587 if (state == GC) return; | 642 if (state == GC) return; |
| 588 | 643 |
| 589 Address js_entry_sp = isolate->js_entry_sp(); | 644 Address js_entry_sp = isolate->js_entry_sp(); |
| 590 if (js_entry_sp == 0) { | 645 if (js_entry_sp == 0) { |
| 591 // Not executing JS now. | 646 // Not executing JS now. |
| 592 return; | 647 return; |
| 593 } | 648 } |
| 594 | 649 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 699 } | 754 } |
| 700 | 755 |
| 701 | 756 |
| 702 #if defined(USE_SIGNALS) | 757 #if defined(USE_SIGNALS) |
| 703 | 758 |
| 704 void Sampler::DoSample() { | 759 void Sampler::DoSample() { |
| 705 if (!SignalHandler::Installed()) return; | 760 if (!SignalHandler::Installed()) return; |
| 706 pthread_kill(platform_data()->vm_tid(), SIGPROF); | 761 pthread_kill(platform_data()->vm_tid(), SIGPROF); |
| 707 } | 762 } |
| 708 | 763 |
| 764 | |
| 765 void Sampler::GetSample(v8::Sample* sample) { | |
| 766 SignalHandler::called_from_get_sample_ = true; | |
| 767 pthread_kill(platform_data()->vm_tid(), SIGPROF); | |
| 768 SignalHandler::sampling_semaphore_->Wait(); | |
| 769 if (SignalHandler::sample_available_) { | |
| 770 sample = new (sample) v8::Sample( | |
| 771 &SignalHandler::sample_.stack[0], | |
| 772 &SignalHandler::sample_.stack[SignalHandler::sample_.frames_count]); | |
| 773 } | |
| 774 SignalHandler::called_from_get_sample_ = false; | |
| 775 } | |
| 776 | |
| 709 #elif V8_OS_WIN || V8_OS_CYGWIN | 777 #elif V8_OS_WIN || V8_OS_CYGWIN |
| 710 | 778 |
| 711 void Sampler::DoSample() { | 779 void Sampler::GetSampleHelper(TickSample* sample, bool called_from_get_sample) { |
|
alph
2014/09/09 13:54:37
nit: you can get rid of the called_from_get_sample
gholap
2014/09/17 02:35:06
Done.
| |
| 712 HANDLE profiled_thread = platform_data()->profiled_thread(); | 780 HANDLE profiled_thread = platform_data()->profiled_thread(); |
| 713 if (profiled_thread == NULL) return; | 781 if (profiled_thread == NULL) return; |
| 714 | 782 |
| 715 #if defined(USE_SIMULATOR) | 783 #if defined(USE_SIMULATOR) |
| 716 SimulatorHelper helper; | 784 SimulatorHelper helper; |
| 717 if (!helper.Init(this, isolate())) return; | 785 if (!helper.Init(this, isolate())) return; |
| 718 #endif | 786 #endif |
| 719 | 787 |
| 720 const DWORD kSuspendFailed = static_cast<DWORD>(-1); | 788 const DWORD kSuspendFailed = static_cast<DWORD>(-1); |
| 721 if (SuspendThread(profiled_thread) == kSuspendFailed) return; | 789 if (SuspendThread(profiled_thread) == kSuspendFailed) return; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 732 #if V8_HOST_ARCH_X64 | 800 #if V8_HOST_ARCH_X64 |
| 733 state.pc = reinterpret_cast<Address>(context.Rip); | 801 state.pc = reinterpret_cast<Address>(context.Rip); |
| 734 state.sp = reinterpret_cast<Address>(context.Rsp); | 802 state.sp = reinterpret_cast<Address>(context.Rsp); |
| 735 state.fp = reinterpret_cast<Address>(context.Rbp); | 803 state.fp = reinterpret_cast<Address>(context.Rbp); |
| 736 #else | 804 #else |
| 737 state.pc = reinterpret_cast<Address>(context.Eip); | 805 state.pc = reinterpret_cast<Address>(context.Eip); |
| 738 state.sp = reinterpret_cast<Address>(context.Esp); | 806 state.sp = reinterpret_cast<Address>(context.Esp); |
| 739 state.fp = reinterpret_cast<Address>(context.Ebp); | 807 state.fp = reinterpret_cast<Address>(context.Ebp); |
| 740 #endif | 808 #endif |
| 741 #endif // USE_SIMULATOR | 809 #endif // USE_SIMULATOR |
| 742 SampleStack(state); | 810 if (called_from_get_sample) { |
| 811 sample->Init(isolate_, state); | |
| 812 } else { | |
| 813 SampleStack(state); | |
| 814 } | |
| 743 } | 815 } |
| 744 ResumeThread(profiled_thread); | 816 ResumeThread(profiled_thread); |
| 745 } | 817 } |
| 746 | 818 |
| 819 | |
| 820 void Sampler::DoSample() { GetSampleHelper(NULL, false); } | |
| 821 | |
| 822 | |
| 823 void Sampler::GetSample(v8::Sample* sample) { | |
| 824 // We need this tick_sample because, | |
| 825 // GetSampleHelper calls Init, which must be called on | |
| 826 // a TickSample and never on Sample. | |
|
alph
2014/09/09 13:54:37
nit: I don't think this comment adds something her
gholap
2014/09/17 02:35:06
Acknowledged.
| |
| 827 TickSample tick_sample; | |
| 828 GetSampleHelper(&tick_sample, true); | |
| 829 sample = new (sample) v8::Sample( | |
| 830 &tick_sample.stack[0], &tick_sample.stack[tick_sample.frames_count]); | |
| 831 } | |
| 832 | |
| 747 #endif // USE_SIGNALS | 833 #endif // USE_SIGNALS |
| 748 | 834 |
| 749 | 835 |
| 750 } } // namespace v8::internal | 836 } } // namespace v8::internal |
| OLD | NEW |