| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 #include <ucontext.h> // walkstack(), getcontext() | 38 #include <ucontext.h> // walkstack(), getcontext() |
| 39 #include <dlfcn.h> // dladdr | 39 #include <dlfcn.h> // dladdr |
| 40 #include <pthread.h> | 40 #include <pthread.h> |
| 41 #include <sched.h> // for sched_yield | 41 #include <sched.h> // for sched_yield |
| 42 #include <semaphore.h> | 42 #include <semaphore.h> |
| 43 #include <time.h> | 43 #include <time.h> |
| 44 #include <sys/time.h> // gettimeofday(), timeradd() | 44 #include <sys/time.h> // gettimeofday(), timeradd() |
| 45 #include <errno.h> | 45 #include <errno.h> |
| 46 #include <ieeefp.h> // finite() | 46 #include <ieeefp.h> // finite() |
| 47 #include <signal.h> // sigemptyset(), etc | 47 #include <signal.h> // sigemptyset(), etc |
| 48 #include <sys/kdi_regs.h> | 48 #include <sys/regset.h> |
| 49 | 49 |
| 50 | 50 |
| 51 #undef MAP_TYPE | 51 #undef MAP_TYPE |
| 52 | 52 |
| 53 #include "v8.h" | 53 #include "v8.h" |
| 54 | 54 |
| 55 #include "platform.h" | 55 #include "platform.h" |
| 56 #include "vm-state-inl.h" | 56 #include "vm-state-inl.h" |
| 57 | 57 |
| 58 | 58 |
| (...skipping 546 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 return new SolarisSemaphore(count); | 605 return new SolarisSemaphore(count); |
| 606 } | 606 } |
| 607 | 607 |
| 608 | 608 |
| 609 #ifdef ENABLE_LOGGING_AND_PROFILING | 609 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 610 | 610 |
| 611 static Sampler* active_sampler_ = NULL; | 611 static Sampler* active_sampler_ = NULL; |
| 612 static pthread_t vm_tid_ = 0; | 612 static pthread_t vm_tid_ = 0; |
| 613 | 613 |
| 614 | 614 |
| 615 static pthread_t GetThreadID() { |
| 616 return pthread_self(); |
| 617 } |
| 618 |
| 619 |
| 615 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | 620 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
| 616 USE(info); | 621 USE(info); |
| 617 if (signal != SIGPROF) return; | 622 if (signal != SIGPROF) return; |
| 618 if (active_sampler_ == NULL || !active_sampler_->IsActive()) return; | 623 if (active_sampler_ == NULL || !active_sampler_->IsActive()) return; |
| 619 if (vm_tid_ != pthread_self()) return; | 624 if (vm_tid_ != GetThreadID()) return; |
| 620 | 625 |
| 621 TickSample sample_obj; | 626 TickSample sample_obj; |
| 622 TickSample* sample = CpuProfiler::TickSampleEvent(); | 627 TickSample* sample = CpuProfiler::TickSampleEvent(); |
| 623 if (sample == NULL) sample = &sample_obj; | 628 if (sample == NULL) sample = &sample_obj; |
| 624 | 629 |
| 625 // Extracting the sample from the context is extremely machine dependent. | 630 // Extracting the sample from the context is extremely machine dependent. |
| 626 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | 631 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
| 627 mcontext_t& mcontext = ucontext->uc_mcontext; | 632 mcontext_t& mcontext = ucontext->uc_mcontext; |
| 628 sample->state = Top::current_vm_state(); | 633 sample->state = Top::current_vm_state(); |
| 629 | 634 |
| 630 #if V8_HOST_ARCH_IA32 | 635 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); |
| 631 sample->pc = reinterpret_cast<Address>(mcontext.gregs[KDIREG_EIP]); | 636 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); |
| 632 sample->sp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_ESP]); | 637 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); |
| 633 sample->fp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_EBP]); | 638 |
| 634 #elif V8_HOST_ARCH_X64 | |
| 635 sample->pc = reinterpret_cast<Address>(mcontext.gregs[KDIREG_RIP]); | |
| 636 sample->sp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_RSP]); | |
| 637 sample->fp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_RBP]); | |
| 638 #else | |
| 639 UNIMPLEMENTED(); | |
| 640 #endif | |
| 641 active_sampler_->SampleStack(sample); | 639 active_sampler_->SampleStack(sample); |
| 642 active_sampler_->Tick(sample); | 640 active_sampler_->Tick(sample); |
| 643 } | 641 } |
| 644 | 642 |
| 645 | 643 |
| 646 class Sampler::PlatformData : public Malloced { | 644 class Sampler::PlatformData : public Malloced { |
| 647 public: | 645 public: |
| 648 PlatformData() { | 646 enum SleepInterval { |
| 649 signal_handler_installed_ = false; | 647 FULL_INTERVAL, |
| 648 HALF_INTERVAL |
| 649 }; |
| 650 |
| 651 explicit PlatformData(Sampler* sampler) |
| 652 : sampler_(sampler), |
| 653 signal_handler_installed_(false), |
| 654 vm_tgid_(getpid()), |
| 655 signal_sender_launched_(false) { |
| 650 } | 656 } |
| 651 | 657 |
| 658 void SignalSender() { |
| 659 while (sampler_->IsActive()) { |
| 660 if (rate_limiter_.SuspendIfNecessary()) continue; |
| 661 if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { |
| 662 SendProfilingSignal(); |
| 663 Sleep(HALF_INTERVAL); |
| 664 RuntimeProfiler::NotifyTick(); |
| 665 Sleep(HALF_INTERVAL); |
| 666 } else { |
| 667 if (sampler_->IsProfiling()) SendProfilingSignal(); |
| 668 if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); |
| 669 Sleep(FULL_INTERVAL); |
| 670 } |
| 671 } |
| 672 } |
| 673 |
| 674 void SendProfilingSignal() { |
| 675 if (!signal_handler_installed_) return; |
| 676 pthread_kill(vm_tid_, SIGPROF); |
| 677 } |
| 678 |
| 679 void Sleep(SleepInterval full_or_half) { |
| 680 // Convert ms to us and subtract 100 us to compensate delays |
| 681 // occuring during signal delivery. |
| 682 useconds_t interval = sampler_->interval_ * 1000 - 100; |
| 683 if (full_or_half == HALF_INTERVAL) interval /= 2; |
| 684 int result = usleep(interval); |
| 685 #ifdef DEBUG |
| 686 if (result != 0 && errno != EINTR) { |
| 687 fprintf(stderr, |
| 688 "SignalSender usleep error; interval = %u, errno = %d\n", |
| 689 interval, |
| 690 errno); |
| 691 ASSERT(result == 0 || errno == EINTR); |
| 692 } |
| 693 #endif |
| 694 USE(result); |
| 695 } |
| 696 |
| 697 Sampler* sampler_; |
| 652 bool signal_handler_installed_; | 698 bool signal_handler_installed_; |
| 653 struct sigaction old_signal_handler_; | 699 struct sigaction old_signal_handler_; |
| 654 struct itimerval old_timer_value_; | 700 int vm_tgid_; |
| 701 bool signal_sender_launched_; |
| 702 pthread_t signal_sender_thread_; |
| 703 RuntimeProfilerRateLimiter rate_limiter_; |
| 655 }; | 704 }; |
| 656 | 705 |
| 657 | 706 |
| 707 static void* SenderEntry(void* arg) { |
| 708 Sampler::PlatformData* data = |
| 709 reinterpret_cast<Sampler::PlatformData*>(arg); |
| 710 data->SignalSender(); |
| 711 return 0; |
| 712 } |
| 713 |
| 714 |
| 658 Sampler::Sampler(int interval) | 715 Sampler::Sampler(int interval) |
| 659 : interval_(interval), | 716 : interval_(interval), |
| 660 profiling_(false), | 717 profiling_(false), |
| 661 active_(false), | 718 active_(false), |
| 662 samples_taken_(0) { | 719 samples_taken_(0) { |
| 663 data_ = new PlatformData(); | 720 data_ = new PlatformData(this); |
| 664 } | 721 } |
| 665 | 722 |
| 666 | 723 |
| 667 Sampler::~Sampler() { | 724 Sampler::~Sampler() { |
| 725 ASSERT(!data_->signal_sender_launched_); |
| 668 delete data_; | 726 delete data_; |
| 669 } | 727 } |
| 670 | 728 |
| 671 | 729 |
| 672 void Sampler::Start() { | 730 void Sampler::Start() { |
| 673 // There can only be one active sampler at the time on POSIX | 731 // There can only be one active sampler at the time on POSIX |
| 674 // platforms. | 732 // platforms. |
| 675 if (active_sampler_ != NULL) return; | 733 ASSERT(!IsActive()); |
| 734 vm_tid_ = GetThreadID(); |
| 676 | 735 |
| 677 // Request profiling signals. | 736 // Request profiling signals. |
| 678 struct sigaction sa; | 737 struct sigaction sa; |
| 679 sa.sa_sigaction = ProfilerSignalHandler; | 738 sa.sa_sigaction = ProfilerSignalHandler; |
| 680 sigemptyset(&sa.sa_mask); | 739 sigemptyset(&sa.sa_mask); |
| 681 sa.sa_flags = SA_SIGINFO; | 740 sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| 682 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; | 741 data_->signal_handler_installed_ = |
| 683 data_->signal_handler_installed_ = true; | 742 sigaction(SIGPROF, &sa, &data_->old_signal_handler_) == 0; |
| 684 | 743 |
| 685 // Set the itimer to generate a tick for each interval. | 744 // Start a thread that sends SIGPROF signal to VM thread. |
| 686 itimerval itimer; | 745 // Sending the signal ourselves instead of relying on itimer provides |
| 687 itimer.it_interval.tv_sec = interval_ / 1000; | 746 // much better accuracy. |
| 688 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000; | 747 SetActive(true); |
| 689 itimer.it_value.tv_sec = itimer.it_interval.tv_sec; | 748 if (pthread_create( |
| 690 itimer.it_value.tv_usec = itimer.it_interval.tv_usec; | 749 &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { |
| 691 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_); | 750 data_->signal_sender_launched_ = true; |
| 751 } |
| 692 | 752 |
| 693 // Set this sampler as the active sampler. | 753 // Set this sampler as the active sampler. |
| 694 active_sampler_ = this; | 754 active_sampler_ = this; |
| 695 active_ = true; | |
| 696 } | 755 } |
| 697 | 756 |
| 698 | 757 |
| 699 void Sampler::Stop() { | 758 void Sampler::Stop() { |
| 759 SetActive(false); |
| 760 |
| 761 // Wait for signal sender termination (it will exit after setting |
| 762 // active_ to false). |
| 763 if (data_->signal_sender_launched_) { |
| 764 Top::WakeUpRuntimeProfilerThreadBeforeShutdown(); |
| 765 pthread_join(data_->signal_sender_thread_, NULL); |
| 766 data_->signal_sender_launched_ = false; |
| 767 } |
| 768 |
| 700 // Restore old signal handler | 769 // Restore old signal handler |
| 701 if (data_->signal_handler_installed_) { | 770 if (data_->signal_handler_installed_) { |
| 702 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL); | |
| 703 sigaction(SIGPROF, &data_->old_signal_handler_, 0); | 771 sigaction(SIGPROF, &data_->old_signal_handler_, 0); |
| 704 data_->signal_handler_installed_ = false; | 772 data_->signal_handler_installed_ = false; |
| 705 } | 773 } |
| 706 | 774 |
| 707 // This sampler is no longer the active sampler. | 775 // This sampler is no longer the active sampler. |
| 708 active_sampler_ = NULL; | 776 active_sampler_ = NULL; |
| 709 active_ = false; | |
| 710 } | 777 } |
| 711 | 778 |
| 712 #endif // ENABLE_LOGGING_AND_PROFILING | 779 #endif // ENABLE_LOGGING_AND_PROFILING |
| 713 | 780 |
| 714 } } // namespace v8::internal | 781 } } // namespace v8::internal |
| OLD | NEW |