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