| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 15 matching lines...) Expand all Loading... |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 // Platform specific code for Linux goes here. For the POSIX comaptible parts | 28 // Platform specific code for Linux goes here. For the POSIX comaptible parts |
| 29 // the implementation is in platform-posix.cc. | 29 // the implementation is in platform-posix.cc. |
| 30 | 30 |
| 31 #include <pthread.h> | 31 #include <pthread.h> |
| 32 #include <semaphore.h> | 32 #include <semaphore.h> |
| 33 #include <signal.h> | 33 #include <signal.h> |
| 34 #include <sys/time.h> | 34 #include <sys/time.h> |
| 35 #include <sys/resource.h> | 35 #include <sys/resource.h> |
| 36 #include <sys/syscall.h> |
| 36 #include <sys/types.h> | 37 #include <sys/types.h> |
| 37 #include <stdlib.h> | 38 #include <stdlib.h> |
| 38 | 39 |
| 39 // Ubuntu Dapper requires memory pages to be marked as | 40 // Ubuntu Dapper requires memory pages to be marked as |
| 40 // executable. Otherwise, OS raises an exception when executing code | 41 // executable. Otherwise, OS raises an exception when executing code |
| 41 // in that page. | 42 // in that page. |
| 42 #include <sys/types.h> // mmap & munmap | 43 #include <sys/types.h> // mmap & munmap |
| 43 #include <sys/mman.h> // mmap & munmap | 44 #include <sys/mman.h> // mmap & munmap |
| 44 #include <sys/stat.h> // open | 45 #include <sys/stat.h> // open |
| 45 #include <fcntl.h> // open | 46 #include <fcntl.h> // open |
| (...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 707 | 708 |
| 708 | 709 |
| 709 Semaphore* OS::CreateSemaphore(int count) { | 710 Semaphore* OS::CreateSemaphore(int count) { |
| 710 return new LinuxSemaphore(count); | 711 return new LinuxSemaphore(count); |
| 711 } | 712 } |
| 712 | 713 |
| 713 | 714 |
| 714 #ifdef ENABLE_LOGGING_AND_PROFILING | 715 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 715 | 716 |
| 716 static Sampler* active_sampler_ = NULL; | 717 static Sampler* active_sampler_ = NULL; |
| 717 static pthread_t vm_thread_ = 0; | |
| 718 | 718 |
| 719 | 719 |
| 720 #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__)) | 720 #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__)) |
| 721 // Android runs a fairly new Linux kernel, so signal info is there, | 721 // Android runs a fairly new Linux kernel, so signal info is there, |
| 722 // but the C library doesn't have the structs defined. | 722 // but the C library doesn't have the structs defined. |
| 723 | 723 |
| 724 struct sigcontext { | 724 struct sigcontext { |
| 725 uint32_t trap_no; | 725 uint32_t trap_no; |
| 726 uint32_t error_code; | 726 uint32_t error_code; |
| 727 uint32_t oldmask; | 727 uint32_t oldmask; |
| 728 uint32_t gregs[16]; | 728 uint32_t gregs[16]; |
| 729 uint32_t arm_cpsr; | 729 uint32_t arm_cpsr; |
| 730 uint32_t fault_address; | 730 uint32_t fault_address; |
| 731 }; | 731 }; |
| 732 typedef uint32_t __sigset_t; | 732 typedef uint32_t __sigset_t; |
| 733 typedef struct sigcontext mcontext_t; | 733 typedef struct sigcontext mcontext_t; |
| 734 typedef struct ucontext { | 734 typedef struct ucontext { |
| 735 uint32_t uc_flags; | 735 uint32_t uc_flags; |
| 736 struct ucontext* uc_link; | 736 struct ucontext* uc_link; |
| 737 stack_t uc_stack; | 737 stack_t uc_stack; |
| 738 mcontext_t uc_mcontext; | 738 mcontext_t uc_mcontext; |
| 739 __sigset_t uc_sigmask; | 739 __sigset_t uc_sigmask; |
| 740 } ucontext_t; | 740 } ucontext_t; |
| 741 enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11}; | 741 enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11}; |
| 742 | 742 |
| 743 #endif | 743 #endif |
| 744 | 744 |
| 745 | 745 |
| 746 // A function that determines if a signal handler is called in the context | |
| 747 // of a VM thread. | |
| 748 // | |
| 749 // The problem is that SIGPROF signal can be delivered to an arbitrary thread | |
| 750 // (see http://code.google.com/p/google-perftools/issues/detail?id=106#c2) | |
| 751 // So, if the signal is being handled in the context of a non-VM thread, | |
| 752 // it means that the VM thread is running, and trying to sample its stack can | |
| 753 // cause a crash. | |
| 754 static inline bool IsVmThread() { | |
| 755 // In the case of a single VM thread, this check is enough. | |
| 756 if (pthread_equal(pthread_self(), vm_thread_)) return true; | |
| 757 // If there are multiple threads that use VM, they must have a thread id | |
| 758 // stored in TLS. To verify that the thread is really executing VM, | |
| 759 // we check Top's data. Having that ThreadManager::RestoreThread first | |
| 760 // restores ThreadLocalTop from TLS, and only then erases the TLS value, | |
| 761 // reading Top::thread_id() should not be affected by races. | |
| 762 if (ThreadManager::HasId() && !ThreadManager::IsArchived() && | |
| 763 ThreadManager::CurrentId() == Top::thread_id()) { | |
| 764 return true; | |
| 765 } | |
| 766 return false; | |
| 767 } | |
| 768 | |
| 769 | |
| 770 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | 746 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
| 771 #ifndef V8_HOST_ARCH_MIPS | 747 #ifndef V8_HOST_ARCH_MIPS |
| 772 USE(info); | 748 USE(info); |
| 773 if (signal != SIGPROF) return; | 749 if (signal != SIGPROF) return; |
| 774 if (active_sampler_ == NULL) return; | 750 if (active_sampler_ == NULL) return; |
| 775 if (!IsVmThread()) return; | |
| 776 | 751 |
| 777 TickSample sample_obj; | 752 TickSample sample_obj; |
| 778 TickSample* sample = CpuProfiler::TickSampleEvent(); | 753 TickSample* sample = CpuProfiler::TickSampleEvent(); |
| 779 if (sample == NULL) sample = &sample_obj; | 754 if (sample == NULL) sample = &sample_obj; |
| 780 | 755 |
| 781 // We always sample the VM state. | 756 // We always sample the VM state. |
| 782 sample->state = VMState::current_state(); | 757 sample->state = VMState::current_state(); |
| 783 | 758 |
| 784 // If profiling, we extract the current pc and sp. | 759 // If profiling, we extract the current pc and sp. |
| 785 if (active_sampler_->IsProfiling()) { | 760 if (active_sampler_->IsProfiling()) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 812 active_sampler_->SampleStack(sample); | 787 active_sampler_->SampleStack(sample); |
| 813 } | 788 } |
| 814 | 789 |
| 815 active_sampler_->Tick(sample); | 790 active_sampler_->Tick(sample); |
| 816 #endif | 791 #endif |
| 817 } | 792 } |
| 818 | 793 |
| 819 | 794 |
| 820 class Sampler::PlatformData : public Malloced { | 795 class Sampler::PlatformData : public Malloced { |
| 821 public: | 796 public: |
| 822 PlatformData() { | 797 explicit PlatformData(Sampler* sampler) |
| 823 signal_handler_installed_ = false; | 798 : sampler_(sampler), |
| 799 signal_handler_installed_(false), |
| 800 vm_tgid_(getpid()), |
| 801 // Glibc doesn't provide a wrapper for gettid(2). |
| 802 vm_tid_(syscall(SYS_gettid)), |
| 803 signal_sender_launched_(false) { |
| 824 } | 804 } |
| 825 | 805 |
| 806 void SignalSender() { |
| 807 while (sampler_->IsActive()) { |
| 808 // Glibc doesn't provide a wrapper for tgkill(2). |
| 809 syscall(SYS_tgkill, vm_tgid_, vm_tid_, SIGPROF); |
| 810 // Convert ms to us and subtract 100 us to compensate delays |
| 811 // occuring during signal delivery. |
| 812 usleep(sampler_->interval_ * 1000 - 100); |
| 813 } |
| 814 } |
| 815 |
| 816 Sampler* sampler_; |
| 826 bool signal_handler_installed_; | 817 bool signal_handler_installed_; |
| 827 struct sigaction old_signal_handler_; | 818 struct sigaction old_signal_handler_; |
| 828 struct itimerval old_timer_value_; | 819 int vm_tgid_; |
| 820 int vm_tid_; |
| 821 bool signal_sender_launched_; |
| 822 pthread_t signal_sender_thread_; |
| 829 }; | 823 }; |
| 830 | 824 |
| 831 | 825 |
| 826 static void* SenderEntry(void* arg) { |
| 827 Sampler::PlatformData* data = |
| 828 reinterpret_cast<Sampler::PlatformData*>(arg); |
| 829 data->SignalSender(); |
| 830 return 0; |
| 831 } |
| 832 |
| 833 |
| 832 Sampler::Sampler(int interval, bool profiling) | 834 Sampler::Sampler(int interval, bool profiling) |
| 833 : interval_(interval), | 835 : interval_(interval), |
| 834 profiling_(profiling), | 836 profiling_(profiling), |
| 835 synchronous_(profiling), | 837 synchronous_(profiling), |
| 836 active_(false) { | 838 active_(false) { |
| 837 data_ = new PlatformData(); | 839 data_ = new PlatformData(this); |
| 838 } | 840 } |
| 839 | 841 |
| 840 | 842 |
| 841 Sampler::~Sampler() { | 843 Sampler::~Sampler() { |
| 842 delete data_; | 844 delete data_; |
| 843 } | 845 } |
| 844 | 846 |
| 845 | 847 |
| 846 void Sampler::Start() { | 848 void Sampler::Start() { |
| 847 // There can only be one active sampler at the time on POSIX | 849 // There can only be one active sampler at the time on POSIX |
| 848 // platforms. | 850 // platforms. |
| 849 if (active_sampler_ != NULL) return; | 851 if (active_sampler_ != NULL) return; |
| 850 | 852 |
| 851 vm_thread_ = pthread_self(); | |
| 852 | |
| 853 // Request profiling signals. | 853 // Request profiling signals. |
| 854 struct sigaction sa; | 854 struct sigaction sa; |
| 855 sa.sa_sigaction = ProfilerSignalHandler; | 855 sa.sa_sigaction = ProfilerSignalHandler; |
| 856 sigemptyset(&sa.sa_mask); | 856 sigemptyset(&sa.sa_mask); |
| 857 sa.sa_flags = SA_SIGINFO; | 857 sa.sa_flags = SA_SIGINFO; |
| 858 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; | 858 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; |
| 859 data_->signal_handler_installed_ = true; | 859 data_->signal_handler_installed_ = true; |
| 860 | 860 |
| 861 // Set the itimer to generate a tick for each interval. | 861 // Start a thread that sends SIGPROF signal to VM thread. |
| 862 itimerval itimer; | 862 // Sending the signal ourselves instead of relying on itimer provides |
| 863 itimer.it_interval.tv_sec = interval_ / 1000; | 863 // much better accuracy. |
| 864 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000; | 864 active_ = true; |
| 865 itimer.it_value.tv_sec = itimer.it_interval.tv_sec; | 865 if (pthread_create( |
| 866 itimer.it_value.tv_usec = itimer.it_interval.tv_usec; | 866 &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { |
| 867 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_); | 867 data_->signal_sender_launched_ = true; |
| 868 } |
| 868 | 869 |
| 869 // Set this sampler as the active sampler. | 870 // Set this sampler as the active sampler. |
| 870 active_sampler_ = this; | 871 active_sampler_ = this; |
| 871 active_ = true; | |
| 872 } | 872 } |
| 873 | 873 |
| 874 | 874 |
| 875 void Sampler::Stop() { | 875 void Sampler::Stop() { |
| 876 active_ = false; |
| 877 |
| 878 // Wait for signal sender termination (it will exit after setting |
| 879 // active_ to false). |
| 880 if (data_->signal_sender_launched_) { |
| 881 pthread_join(data_->signal_sender_thread_, NULL); |
| 882 data_->signal_sender_launched_ = false; |
| 883 } |
| 884 |
| 876 // Restore old signal handler | 885 // Restore old signal handler |
| 877 if (data_->signal_handler_installed_) { | 886 if (data_->signal_handler_installed_) { |
| 878 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL); | |
| 879 sigaction(SIGPROF, &data_->old_signal_handler_, 0); | 887 sigaction(SIGPROF, &data_->old_signal_handler_, 0); |
| 880 data_->signal_handler_installed_ = false; | 888 data_->signal_handler_installed_ = false; |
| 881 } | 889 } |
| 882 | 890 |
| 883 // This sampler is no longer the active sampler. | 891 // This sampler is no longer the active sampler. |
| 884 active_sampler_ = NULL; | 892 active_sampler_ = NULL; |
| 885 active_ = false; | |
| 886 } | 893 } |
| 887 | 894 |
| 888 | 895 |
| 889 #endif // ENABLE_LOGGING_AND_PROFILING | 896 #endif // ENABLE_LOGGING_AND_PROFILING |
| 890 | 897 |
| 891 } } // namespace v8::internal | 898 } } // namespace v8::internal |
| OLD | NEW |