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 | |
| 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 20 matching lines...) Expand all Loading... | |
| 35 !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) | 34 !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) |
| 36 #include <asm/sigcontext.h> // NOLINT | 35 #include <asm/sigcontext.h> // NOLINT |
| 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 |
| 44 #include "include/v8-sampler.h" | |
| 45 | |
| 45 #include "src/v8.h" | 46 #include "src/v8.h" |
| 46 | 47 |
| 47 #include "src/base/platform/platform.h" | 48 #include "src/base/platform/platform.h" |
| 48 #include "src/cpu-profiler-inl.h" | 49 #include "src/cpu-profiler-inl.h" |
| 49 #include "src/flags.h" | 50 #include "src/flags.h" |
| 50 #include "src/frames-inl.h" | 51 #include "src/frames-inl.h" |
| 51 #include "src/log.h" | 52 #include "src/log.h" |
| 52 #include "src/simulator.h" | 53 #include "src/simulator.h" |
| 53 #include "src/v8threads.h" | 54 #include "src/v8threads.h" |
| 54 #include "src/vm-state-inl.h" | 55 #include "src/vm-state-inl.h" |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 private: | 263 private: |
| 263 Simulator* simulator_; | 264 Simulator* simulator_; |
| 264 }; | 265 }; |
| 265 #endif // USE_SIMULATOR | 266 #endif // USE_SIMULATOR |
| 266 | 267 |
| 267 | 268 |
| 268 #if defined(USE_SIGNALS) | 269 #if defined(USE_SIGNALS) |
| 269 | 270 |
| 270 class SignalHandler : public AllStatic { | 271 class SignalHandler : public AllStatic { |
| 271 public: | 272 public: |
| 272 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } | 273 static void SetUp() { |
| 273 static void TearDown() { delete mutex_; } | 274 CHECK(mutex_ == NULL); |
|
Benedikt Meurer
2014/08/18 04:22:04
Nit: DCHECK_EQ(NULL, mutex_)
gholap
2014/08/18 19:51:59
Done.
| |
| 275 CHECK(sampling_semaphore_ == NULL); | |
|
Benedikt Meurer
2014/08/18 04:22:04
Nit: DCHECK_EQ(NULL, sampling_semaphore_)
gholap
2014/08/18 19:52:00
Done.
| |
| 276 | |
| 277 mutex_ = new base::Mutex(); | |
| 278 sampling_semaphore_ = new base::Semaphore(0); | |
| 279 } | |
| 280 | |
| 281 static void TearDown() { | |
| 282 delete mutex_; | |
| 283 delete sampling_semaphore_; | |
| 284 | |
| 285 mutex_ = NULL; | |
| 286 sampling_semaphore_ = NULL; | |
| 287 } | |
| 274 | 288 |
| 275 static void IncreaseSamplerCount() { | 289 static void IncreaseSamplerCount() { |
| 276 base::LockGuard<base::Mutex> lock_guard(mutex_); | 290 base::LockGuard<base::Mutex> lock_guard(mutex_); |
| 277 if (++client_count_ == 1) Install(); | 291 if (++client_count_ == 1) Install(); |
| 278 } | 292 } |
| 279 | 293 |
| 280 static void DecreaseSamplerCount() { | 294 static void DecreaseSamplerCount() { |
| 281 base::LockGuard<base::Mutex> lock_guard(mutex_); | 295 base::LockGuard<base::Mutex> lock_guard(mutex_); |
| 282 if (--client_count_ == 0) Restore(); | 296 if (--client_count_ == 0) Restore(); |
| 283 } | 297 } |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 301 } | 315 } |
| 302 | 316 |
| 303 static void Restore() { | 317 static void Restore() { |
| 304 if (signal_handler_installed_) { | 318 if (signal_handler_installed_) { |
| 305 sigaction(SIGPROF, &old_signal_handler_, 0); | 319 sigaction(SIGPROF, &old_signal_handler_, 0); |
| 306 signal_handler_installed_ = false; | 320 signal_handler_installed_ = false; |
| 307 } | 321 } |
| 308 } | 322 } |
| 309 | 323 |
| 310 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); | 324 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); |
| 325 | |
| 326 // The SIGPROF could have come from DoSample or from GetSample. | |
| 327 // GetSample is the internal endpoint for the public | |
| 328 // GetSample API, which aims to bypass all the internal buffers | |
| 329 // and return just one sample instead, rightaway. | |
| 330 // TODO(gholap): Eventually, get rid of DoSample. | |
| 331 // Only GetSample should remain. | |
| 332 | |
| 333 // This is the sample which will be filled by the call from GetSample. | |
| 334 static TickSample sample_; | |
| 335 | |
| 336 // For the SIGPROF handler to know whether the call was from GetSample. | |
| 337 static volatile bool called_from_get_sample_; | |
| 338 | |
| 339 // GetSample waits synchronously till the SIGPROF handler returns. | |
| 340 // this semaphore is used to signal GetSample. | |
| 341 static base::Semaphore* sampling_semaphore_; | |
| 342 | |
| 343 // It is not that every time HandleProfilerSignal is invoked, | |
| 344 // it succeeds in obtaining a sample. | |
| 345 // This provides GetSample with the information whether | |
| 346 // the handler finished with or without getting the sample. | |
| 347 static bool sample_available_; | |
| 348 | |
| 311 // Protects the process wide state below. | 349 // Protects the process wide state below. |
| 312 static base::Mutex* mutex_; | 350 static base::Mutex* mutex_; |
| 313 static int client_count_; | 351 static int client_count_; |
| 314 static bool signal_handler_installed_; | 352 static bool signal_handler_installed_; |
| 315 static struct sigaction old_signal_handler_; | 353 static struct sigaction old_signal_handler_; |
| 354 | |
| 355 friend class Sampler; | |
| 316 }; | 356 }; |
| 317 | 357 |
| 318 | 358 |
| 359 TickSample SignalHandler::sample_; | |
| 360 volatile bool SignalHandler::called_from_get_sample_ = false; | |
| 361 base::Semaphore* SignalHandler::sampling_semaphore_ = NULL; | |
| 362 bool SignalHandler::sample_available_ = false; | |
| 363 | |
| 319 base::Mutex* SignalHandler::mutex_ = NULL; | 364 base::Mutex* SignalHandler::mutex_ = NULL; |
| 320 int SignalHandler::client_count_ = 0; | 365 int SignalHandler::client_count_ = 0; |
| 321 struct sigaction SignalHandler::old_signal_handler_; | 366 struct sigaction SignalHandler::old_signal_handler_; |
| 322 bool SignalHandler::signal_handler_installed_ = false; | 367 bool SignalHandler::signal_handler_installed_ = false; |
| 323 | 368 |
| 324 | 369 |
| 325 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, | 370 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, |
| 326 void* context) { | 371 void* context) { |
| 327 #if V8_OS_NACL | 372 #if V8_OS_NACL |
| 328 // As Native Client does not support signal handling, profiling | 373 // As Native Client does not support signal handling, profiling |
| 329 // is disabled. | 374 // is disabled. |
| 330 return; | 375 return; |
| 331 #else | 376 #else |
| 377 // Even if we return prematurely, | |
| 378 // we need to signal the sampling_semaphore_ | |
| 379 sample_available_ = false; | |
| 380 ScopedSemaphore scoped_semaphore(sampling_semaphore_); | |
| 381 | |
| 332 USE(info); | 382 USE(info); |
| 333 if (signal != SIGPROF) return; | 383 if (signal != SIGPROF) return; |
| 334 Isolate* isolate = Isolate::UncheckedReentrantCurrent(); | 384 Isolate* isolate = Isolate::UncheckedReentrantCurrent(); |
| 335 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { | 385 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { |
| 336 // We require a fully initialized and entered isolate. | 386 // We require a fully initialized and entered isolate. |
| 337 return; | 387 return; |
| 338 } | 388 } |
| 339 if (v8::Locker::IsActive() && | 389 if (v8::Locker::IsActive() && |
| 340 !isolate->thread_manager()->IsLockedByCurrentThread()) { | 390 !isolate->thread_manager()->IsLockedByCurrentThread()) { |
| 341 return; | 391 return; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 459 state.pc = reinterpret_cast<Address>(mcontext.cpu.eip); | 509 state.pc = reinterpret_cast<Address>(mcontext.cpu.eip); |
| 460 state.sp = reinterpret_cast<Address>(mcontext.cpu.esp); | 510 state.sp = reinterpret_cast<Address>(mcontext.cpu.esp); |
| 461 state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp); | 511 state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp); |
| 462 #elif V8_HOST_ARCH_ARM | 512 #elif V8_HOST_ARCH_ARM |
| 463 state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]); | 513 state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]); |
| 464 state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]); | 514 state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]); |
| 465 state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]); | 515 state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]); |
| 466 #endif // V8_HOST_ARCH_* | 516 #endif // V8_HOST_ARCH_* |
| 467 #endif // V8_OS_QNX | 517 #endif // V8_OS_QNX |
| 468 #endif // USE_SIMULATOR | 518 #endif // USE_SIMULATOR |
| 469 sampler->SampleStack(state); | 519 if (called_from_get_sample_) { |
| 520 sample_.Init(sampler->isolate(), state); | |
| 521 } else { | |
| 522 sampler->SampleStack(state); | |
| 523 } | |
| 524 sample_available_ = true; | |
| 470 #endif // V8_OS_NACL | 525 #endif // V8_OS_NACL |
| 471 } | 526 } |
| 472 | 527 |
| 473 #endif | 528 #endif |
| 474 | 529 |
| 475 | 530 |
| 476 class SamplerThread : public base::Thread { | 531 class SamplerThread : public base::Thread { |
| 477 public: | 532 public: |
| 478 static const int kSamplerThreadStackSize = 64 * KB; | 533 static const int kSamplerThreadStackSize = 64 * KB; |
| 479 | 534 |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 679 ++js_and_external_sample_count_; | 734 ++js_and_external_sample_count_; |
| 680 } | 735 } |
| 681 } | 736 } |
| 682 Tick(sample); | 737 Tick(sample); |
| 683 if (sample != &sample_obj) { | 738 if (sample != &sample_obj) { |
| 684 isolate_->cpu_profiler()->FinishTickSample(); | 739 isolate_->cpu_profiler()->FinishTickSample(); |
| 685 } | 740 } |
| 686 } | 741 } |
| 687 | 742 |
| 688 | 743 |
| 744 void Sampler::CopyTickSampleToSample(TickSample* tick_sample, | |
| 745 v8::Sample* sample) { | |
| 746 for (int i = 0; i < tick_sample->frames_count; i++) { | |
| 747 sample->stack[i] = tick_sample->stack[i]; | |
| 748 } | |
| 749 sample->frames_count = tick_sample->frames_count; | |
| 750 } | |
| 751 | |
| 752 | |
| 689 #if defined(USE_SIGNALS) | 753 #if defined(USE_SIGNALS) |
| 690 | 754 |
| 691 void Sampler::DoSample() { | 755 void Sampler::DoSample() { |
| 692 if (!SignalHandler::Installed()) return; | 756 if (!SignalHandler::Installed()) return; |
| 693 pthread_kill(platform_data()->vm_tid(), SIGPROF); | 757 pthread_kill(platform_data()->vm_tid(), SIGPROF); |
| 694 } | 758 } |
| 695 | 759 |
| 760 | |
| 761 v8::Sample* Sampler::GetSample(v8::Sample* sample) { | |
| 762 if (!SignalHandler::Installed()) return NULL; | |
| 763 SignalHandler::called_from_get_sample_ = true; | |
| 764 pthread_kill(platform_data()->vm_tid(), SIGPROF); | |
| 765 SignalHandler::sampling_semaphore_->Wait(); | |
| 766 if (SignalHandler::sample_available_) { | |
| 767 CopyTickSampleToSample(&SignalHandler::sample_, sample); | |
| 768 } else { | |
| 769 sample = NULL; | |
| 770 } | |
| 771 SignalHandler::called_from_get_sample_ = false; | |
| 772 return sample; | |
| 773 } | |
| 774 | |
| 696 #elif V8_OS_WIN || V8_OS_CYGWIN | 775 #elif V8_OS_WIN || V8_OS_CYGWIN |
| 697 | 776 |
| 698 void Sampler::DoSample() { | 777 void Sampler::GetSampleHelper(TickSample * sample, |
| 778 bool called_from_get_sample) { | |
| 699 HANDLE profiled_thread = platform_data()->profiled_thread(); | 779 HANDLE profiled_thread = platform_data()->profiled_thread(); |
| 700 if (profiled_thread == NULL) return; | 780 if (profiled_thread == NULL) return NULL; |
| 701 | 781 |
| 702 #if defined(USE_SIMULATOR) | 782 #if defined(USE_SIMULATOR) |
| 703 SimulatorHelper helper; | 783 SimulatorHelper helper; |
| 704 if (!helper.Init(this, isolate())) return; | 784 if (!helper.Init(this, isolate())) return NULL; |
| 705 #endif | 785 #endif |
| 706 | 786 |
| 707 const DWORD kSuspendFailed = static_cast<DWORD>(-1); | 787 const DWORD kSuspendFailed = static_cast<DWORD>(-1); |
| 708 if (SuspendThread(profiled_thread) == kSuspendFailed) return; | 788 if (SuspendThread(profiled_thread) == kSuspendFailed) return NULL; |
| 709 | 789 |
| 710 // Context used for sampling the register state of the profiled thread. | 790 // Context used for sampling the register state of the profiled thread. |
| 711 CONTEXT context; | 791 CONTEXT context; |
| 712 memset(&context, 0, sizeof(context)); | 792 memset(&context, 0, sizeof(context)); |
| 713 context.ContextFlags = CONTEXT_FULL; | 793 context.ContextFlags = CONTEXT_FULL; |
| 714 if (GetThreadContext(profiled_thread, &context) != 0) { | 794 if (GetThreadContext(profiled_thread, &context) != 0) { |
| 715 RegisterState state; | 795 RegisterState state; |
| 716 #if defined(USE_SIMULATOR) | 796 #if defined(USE_SIMULATOR) |
| 717 helper.FillRegisters(&state); | 797 helper.FillRegisters(&state); |
| 718 #else | 798 #else |
| 719 #if V8_HOST_ARCH_X64 | 799 #if V8_HOST_ARCH_X64 |
| 720 state.pc = reinterpret_cast<Address>(context.Rip); | 800 state.pc = reinterpret_cast<Address>(context.Rip); |
| 721 state.sp = reinterpret_cast<Address>(context.Rsp); | 801 state.sp = reinterpret_cast<Address>(context.Rsp); |
| 722 state.fp = reinterpret_cast<Address>(context.Rbp); | 802 state.fp = reinterpret_cast<Address>(context.Rbp); |
| 723 #else | 803 #else |
| 724 state.pc = reinterpret_cast<Address>(context.Eip); | 804 state.pc = reinterpret_cast<Address>(context.Eip); |
| 725 state.sp = reinterpret_cast<Address>(context.Esp); | 805 state.sp = reinterpret_cast<Address>(context.Esp); |
| 726 state.fp = reinterpret_cast<Address>(context.Ebp); | 806 state.fp = reinterpret_cast<Address>(context.Ebp); |
| 727 #endif | 807 #endif |
| 728 #endif // USE_SIMULATOR | 808 #endif // USE_SIMULATOR |
| 729 SampleStack(state); | 809 if (called_from_get_sample) { |
| 810 sample->Init(sampler->isolate(), state); | |
| 811 } else { | |
| 812 SampleStack(state); | |
| 813 } | |
| 730 } | 814 } |
| 731 ResumeThread(profiled_thread); | 815 ResumeThread(profiled_thread); |
| 732 } | 816 } |
| 733 | 817 |
| 818 | |
| 819 void Sampler::DoSample() { | |
| 820 GetSampleHelper(NULL, false); | |
| 821 } | |
| 822 | |
| 823 | |
| 824 v8::Sample* Sampler::GetSample(v8::Sample* sample) { | |
| 825 // We need this tick_sample because, | |
| 826 // GetSampleHelper calls Init, which must be called on | |
| 827 // a TickSample and never on Sample. | |
| 828 TickSample tick_sample; | |
| 829 GetSampleHelper(&tick_sample, true); | |
| 830 CopyTickSampleToSample(&tick_sample, sample); | |
| 831 return sample; | |
| 832 } | |
| 833 | |
| 734 #endif // USE_SIGNALS | 834 #endif // USE_SIGNALS |
| 735 | 835 |
| 736 | 836 |
| 737 } } // namespace v8::internal | 837 } } // namespace v8::internal |
| OLD | NEW |