| 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 #include <strings.h> // index | 51 #include <strings.h> // index |
| 52 #include <errno.h> | 52 #include <errno.h> |
| 53 #include <stdarg.h> | 53 #include <stdarg.h> |
| 54 | 54 |
| 55 #undef MAP_TYPE | 55 #undef MAP_TYPE |
| 56 | 56 |
| 57 #include "v8.h" | 57 #include "v8.h" |
| 58 | 58 |
| 59 #include "platform.h" | 59 #include "platform.h" |
| 60 #include "v8threads.h" | 60 #include "v8threads.h" |
| 61 #include "vm-state-inl.h" |
| 61 | 62 |
| 62 | 63 |
| 63 namespace v8 { | 64 namespace v8 { |
| 64 namespace internal { | 65 namespace internal { |
| 65 | 66 |
| 66 // 0 is never a valid thread id on Linux since tids and pids share a | 67 // 0 is never a valid thread id on Linux since tids and pids share a |
| 67 // name space and pid 0 is reserved (see man 2 kill). | 68 // name space and pid 0 is reserved (see man 2 kill). |
| 68 static const pthread_t kNoThread = (pthread_t) 0; | 69 static const pthread_t kNoThread = (pthread_t) 0; |
| 69 | 70 |
| 70 | 71 |
| (...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 virtual int Lock() { | 654 virtual int Lock() { |
| 654 int result = pthread_mutex_lock(&mutex_); | 655 int result = pthread_mutex_lock(&mutex_); |
| 655 return result; | 656 return result; |
| 656 } | 657 } |
| 657 | 658 |
| 658 virtual int Unlock() { | 659 virtual int Unlock() { |
| 659 int result = pthread_mutex_unlock(&mutex_); | 660 int result = pthread_mutex_unlock(&mutex_); |
| 660 return result; | 661 return result; |
| 661 } | 662 } |
| 662 | 663 |
| 664 virtual bool TryLock() { |
| 665 int result = pthread_mutex_trylock(&mutex_); |
| 666 // Return false if the lock is busy and locking failed. |
| 667 if (result == EBUSY) { |
| 668 return false; |
| 669 } |
| 670 ASSERT(result == 0); // Verify no other errors. |
| 671 return true; |
| 672 } |
| 673 |
| 663 private: | 674 private: |
| 664 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms. | 675 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms. |
| 665 }; | 676 }; |
| 666 | 677 |
| 667 | 678 |
| 668 Mutex* OS::CreateMutex() { | 679 Mutex* OS::CreateMutex() { |
| 669 return new LinuxMutex(); | 680 return new LinuxMutex(); |
| 670 } | 681 } |
| 671 | 682 |
| 672 | 683 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 } | 746 } |
| 736 | 747 |
| 737 | 748 |
| 738 Semaphore* OS::CreateSemaphore(int count) { | 749 Semaphore* OS::CreateSemaphore(int count) { |
| 739 return new LinuxSemaphore(count); | 750 return new LinuxSemaphore(count); |
| 740 } | 751 } |
| 741 | 752 |
| 742 | 753 |
| 743 #ifdef ENABLE_LOGGING_AND_PROFILING | 754 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 744 | 755 |
| 745 static Sampler* active_sampler_ = NULL; | |
| 746 | |
| 747 | |
| 748 #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__)) | 756 #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__)) |
| 749 // Android runs a fairly new Linux kernel, so signal info is there, | 757 // Android runs a fairly new Linux kernel, so signal info is there, |
| 750 // but the C library doesn't have the structs defined. | 758 // but the C library doesn't have the structs defined. |
| 751 | 759 |
| 752 struct sigcontext { | 760 struct sigcontext { |
| 753 uint32_t trap_no; | 761 uint32_t trap_no; |
| 754 uint32_t error_code; | 762 uint32_t error_code; |
| 755 uint32_t oldmask; | 763 uint32_t oldmask; |
| 756 uint32_t gregs[16]; | 764 uint32_t gregs[16]; |
| 757 uint32_t arm_cpsr; | 765 uint32_t arm_cpsr; |
| 758 uint32_t fault_address; | 766 uint32_t fault_address; |
| 759 }; | 767 }; |
| 760 typedef uint32_t __sigset_t; | 768 typedef uint32_t __sigset_t; |
| 761 typedef struct sigcontext mcontext_t; | 769 typedef struct sigcontext mcontext_t; |
| 762 typedef struct ucontext { | 770 typedef struct ucontext { |
| 763 uint32_t uc_flags; | 771 uint32_t uc_flags; |
| 764 struct ucontext* uc_link; | 772 struct ucontext* uc_link; |
| 765 stack_t uc_stack; | 773 stack_t uc_stack; |
| 766 mcontext_t uc_mcontext; | 774 mcontext_t uc_mcontext; |
| 767 __sigset_t uc_sigmask; | 775 __sigset_t uc_sigmask; |
| 768 } ucontext_t; | 776 } ucontext_t; |
| 769 enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11}; | 777 enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11}; |
| 770 | 778 |
| 771 #endif | 779 #endif |
| 772 | 780 |
| 773 | 781 |
| 782 static int GetThreadID() { |
| 783 // Glibc doesn't provide a wrapper for gettid(2). |
| 784 return syscall(SYS_gettid); |
| 785 } |
| 786 |
| 787 |
| 774 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | 788 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
| 775 #ifndef V8_HOST_ARCH_MIPS | 789 #ifndef V8_HOST_ARCH_MIPS |
| 776 USE(info); | 790 USE(info); |
| 777 if (signal != SIGPROF) return; | 791 if (signal != SIGPROF) return; |
| 778 if (active_sampler_ == NULL) return; | 792 Isolate* isolate = Isolate::UncheckedCurrent(); |
| 793 if (isolate == NULL || !isolate->IsInUse()) return; |
| 794 Sampler* sampler = isolate->logger()->sampler(); |
| 795 if (sampler == NULL || !sampler->IsActive()) return; |
| 779 | 796 |
| 780 TickSample sample_obj; | 797 TickSample sample_obj; |
| 781 TickSample* sample = CpuProfiler::TickSampleEvent(); | 798 TickSample* sample = CpuProfiler::TickSampleEvent(isolate); |
| 782 if (sample == NULL) sample = &sample_obj; | 799 if (sample == NULL) sample = &sample_obj; |
| 783 | 800 |
| 784 // We always sample the VM state. | 801 // Extracting the sample from the context is extremely machine dependent. |
| 785 sample->state = VMState::current_state(); | 802 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
| 786 | 803 mcontext_t& mcontext = ucontext->uc_mcontext; |
| 787 // If profiling, we extract the current pc and sp. | 804 sample->state = isolate->current_vm_state(); |
| 788 if (active_sampler_->IsProfiling()) { | |
| 789 // Extracting the sample from the context is extremely machine dependent. | |
| 790 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | |
| 791 mcontext_t& mcontext = ucontext->uc_mcontext; | |
| 792 #if V8_HOST_ARCH_IA32 | 805 #if V8_HOST_ARCH_IA32 |
| 793 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); | 806 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); |
| 794 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); | 807 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); |
| 795 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]); | 808 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]); |
| 796 #elif V8_HOST_ARCH_X64 | 809 #elif V8_HOST_ARCH_X64 |
| 797 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]); | 810 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]); |
| 798 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]); | 811 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]); |
| 799 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]); | 812 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]); |
| 800 #elif V8_HOST_ARCH_ARM | 813 #elif V8_HOST_ARCH_ARM |
| 801 // An undefined macro evaluates to 0, so this applies to Android's Bionic also. | 814 // An undefined macro evaluates to 0, so this applies to Android's Bionic also. |
| 802 #if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) | 815 #if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) |
| 803 sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]); | 816 sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]); |
| 804 sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]); | 817 sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]); |
| 805 sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]); | 818 sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]); |
| 806 #else | 819 #else |
| 807 sample->pc = reinterpret_cast<Address>(mcontext.arm_pc); | 820 sample->pc = reinterpret_cast<Address>(mcontext.arm_pc); |
| 808 sample->sp = reinterpret_cast<Address>(mcontext.arm_sp); | 821 sample->sp = reinterpret_cast<Address>(mcontext.arm_sp); |
| 809 sample->fp = reinterpret_cast<Address>(mcontext.arm_fp); | 822 sample->fp = reinterpret_cast<Address>(mcontext.arm_fp); |
| 810 #endif | 823 #endif |
| 811 #elif V8_HOST_ARCH_MIPS | 824 #elif V8_HOST_ARCH_MIPS |
| 812 // Implement this on MIPS. | 825 // Implement this on MIPS. |
| 813 UNIMPLEMENTED(); | 826 UNIMPLEMENTED(); |
| 814 #endif | 827 #endif |
| 815 active_sampler_->SampleStack(sample); | 828 sampler->SampleStack(sample); |
| 816 } | 829 sampler->Tick(sample); |
| 817 | |
| 818 active_sampler_->Tick(sample); | |
| 819 #endif | 830 #endif |
| 820 } | 831 } |
| 821 | 832 |
| 822 | 833 |
| 823 class Sampler::PlatformData : public Malloced { | 834 class Sampler::PlatformData : public Malloced { |
| 824 public: | 835 public: |
| 825 explicit PlatformData(Sampler* sampler) | 836 PlatformData() : vm_tid_(GetThreadID()) {} |
| 826 : sampler_(sampler), | 837 |
| 827 signal_handler_installed_(false), | 838 int vm_tid() const { return vm_tid_; } |
| 828 vm_tgid_(getpid()), | 839 |
| 829 // Glibc doesn't provide a wrapper for gettid(2). | 840 private: |
| 830 vm_tid_(syscall(SYS_gettid)), | 841 const int vm_tid_; |
| 831 signal_sender_launched_(false) { | 842 }; |
| 832 } | 843 |
| 833 | 844 |
| 834 void SignalSender() { | 845 class SignalSender : public Thread { |
| 835 while (sampler_->IsActive()) { | 846 public: |
| 836 // Glibc doesn't provide a wrapper for tgkill(2). | 847 enum SleepInterval { |
| 837 syscall(SYS_tgkill, vm_tgid_, vm_tid_, SIGPROF); | 848 HALF_INTERVAL, |
| 838 // Convert ms to us and subtract 100 us to compensate delays | 849 FULL_INTERVAL |
| 839 // occuring during signal delivery. | 850 }; |
| 840 const useconds_t interval = sampler_->interval_ * 1000 - 100; | 851 |
| 841 int result = usleep(interval); | 852 explicit SignalSender(int interval) |
| 853 : Thread(NULL), vm_tgid_(getpid()), interval_(interval) {} |
| 854 |
| 855 static void AddActiveSampler(Sampler* sampler) { |
| 856 ScopedLock lock(mutex_); |
| 857 SamplerRegistry::AddActiveSampler(sampler); |
| 858 if (instance_ == NULL) { |
| 859 // Install a signal handler. |
| 860 struct sigaction sa; |
| 861 sa.sa_sigaction = ProfilerSignalHandler; |
| 862 sigemptyset(&sa.sa_mask); |
| 863 sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| 864 signal_handler_installed_ = |
| 865 (sigaction(SIGPROF, &sa, &old_signal_handler_) != 0); |
| 866 |
| 867 // Start a thread that sends SIGPROF signal to VM threads. |
| 868 instance_ = new SignalSender(sampler->interval()); |
| 869 instance_->Start(); |
| 870 } else { |
| 871 ASSERT(instance_->interval_ == sampler->interval()); |
| 872 } |
| 873 } |
| 874 |
| 875 static void RemoveActiveSampler(Sampler* sampler) { |
| 876 ScopedLock lock(mutex_); |
| 877 SamplerRegistry::RemoveActiveSampler(sampler); |
| 878 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { |
| 879 RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown(); |
| 880 instance_->Join(); |
| 881 delete instance_; |
| 882 instance_ = NULL; |
| 883 |
| 884 // Restore the old signal handler. |
| 885 if (signal_handler_installed_) { |
| 886 sigaction(SIGPROF, &old_signal_handler_, 0); |
| 887 signal_handler_installed_ = false; |
| 888 } |
| 889 } |
| 890 } |
| 891 |
| 892 // Implement Thread::Run(). |
| 893 virtual void Run() { |
| 894 SamplerRegistry::State state = SamplerRegistry::GetState(); |
| 895 while (state != SamplerRegistry::HAS_NO_SAMPLERS) { |
| 896 bool cpu_profiling_enabled = |
| 897 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); |
| 898 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); |
| 899 // When CPU profiling is enabled both JavaScript and C++ code is |
| 900 // profiled. We must not suspend. |
| 901 if (!cpu_profiling_enabled) { |
| 902 if (rate_limiter_.SuspendIfNecessary()) continue; |
| 903 } |
| 904 if (cpu_profiling_enabled && runtime_profiler_enabled) { |
| 905 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { |
| 906 return; |
| 907 } |
| 908 Sleep(HALF_INTERVAL); |
| 909 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { |
| 910 return; |
| 911 } |
| 912 Sleep(HALF_INTERVAL); |
| 913 } else { |
| 914 if (cpu_profiling_enabled) { |
| 915 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, |
| 916 this)) { |
| 917 return; |
| 918 } |
| 919 } |
| 920 if (runtime_profiler_enabled) { |
| 921 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, |
| 922 NULL)) { |
| 923 return; |
| 924 } |
| 925 } |
| 926 Sleep(FULL_INTERVAL); |
| 927 } |
| 928 } |
| 929 } |
| 930 |
| 931 static void DoCpuProfile(Sampler* sampler, void* raw_sender) { |
| 932 if (!sampler->IsProfiling()) return; |
| 933 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender); |
| 934 sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); |
| 935 } |
| 936 |
| 937 static void DoRuntimeProfile(Sampler* sampler, void* ignored) { |
| 938 if (!sampler->isolate()->IsInitialized()) return; |
| 939 sampler->isolate()->runtime_profiler()->NotifyTick(); |
| 940 } |
| 941 |
| 942 void SendProfilingSignal(int tid) { |
| 943 // Glibc doesn't provide a wrapper for tgkill(2). |
| 944 syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF); |
| 945 } |
| 946 |
| 947 void Sleep(SleepInterval full_or_half) { |
| 948 // Convert ms to us and subtract 100 us to compensate delays |
| 949 // occuring during signal delivery. |
| 950 useconds_t interval = interval_ * 1000 - 100; |
| 951 if (full_or_half == HALF_INTERVAL) interval /= 2; |
| 952 int result = usleep(interval); |
| 842 #ifdef DEBUG | 953 #ifdef DEBUG |
| 843 if (result != 0 && errno != EINTR) { | 954 if (result != 0 && errno != EINTR) { |
| 844 fprintf(stderr, | 955 fprintf(stderr, |
| 845 "SignalSender usleep error; interval = %u, errno = %d\n", | 956 "SignalSender usleep error; interval = %u, errno = %d\n", |
| 846 interval, | 957 interval, |
| 847 errno); | 958 errno); |
| 848 ASSERT(result == 0 || errno == EINTR); | 959 ASSERT(result == 0 || errno == EINTR); |
| 849 } | 960 } |
| 850 #endif | 961 #endif |
| 851 USE(result); | 962 USE(result); |
| 852 } | 963 } |
| 853 } | 964 |
| 854 | 965 const int vm_tgid_; |
| 855 Sampler* sampler_; | 966 const int interval_; |
| 856 bool signal_handler_installed_; | 967 RuntimeProfilerRateLimiter rate_limiter_; |
| 857 struct sigaction old_signal_handler_; | 968 |
| 858 int vm_tgid_; | 969 // Protects the process wide state below. |
| 859 int vm_tid_; | 970 static Mutex* mutex_; |
| 860 bool signal_sender_launched_; | 971 static SignalSender* instance_; |
| 861 pthread_t signal_sender_thread_; | 972 static bool signal_handler_installed_; |
| 973 static struct sigaction old_signal_handler_; |
| 974 |
| 975 DISALLOW_COPY_AND_ASSIGN(SignalSender); |
| 862 }; | 976 }; |
| 863 | 977 |
| 864 | 978 |
| 865 static void* SenderEntry(void* arg) { | 979 Mutex* SignalSender::mutex_ = OS::CreateMutex(); |
| 866 Sampler::PlatformData* data = | 980 SignalSender* SignalSender::instance_ = NULL; |
| 867 reinterpret_cast<Sampler::PlatformData*>(arg); | 981 struct sigaction SignalSender::old_signal_handler_; |
| 868 data->SignalSender(); | 982 bool SignalSender::signal_handler_installed_ = false; |
| 869 return 0; | 983 |
| 870 } | 984 |
| 871 | 985 Sampler::Sampler(Isolate* isolate, int interval) |
| 872 | |
| 873 Sampler::Sampler(Isolate* isolate, int interval, bool profiling) | |
| 874 : isolate_(isolate), | 986 : isolate_(isolate), |
| 875 interval_(interval), | 987 interval_(interval), |
| 876 synchronous_(profiling), | 988 profiling_(false), |
| 877 profiling_(profiling), | |
| 878 active_(false), | 989 active_(false), |
| 879 samples_taken_(0) { | 990 samples_taken_(0) { |
| 880 data_ = new PlatformData(this); | 991 data_ = new PlatformData; |
| 881 } | 992 } |
| 882 | 993 |
| 883 | 994 |
| 884 Sampler::~Sampler() { | 995 Sampler::~Sampler() { |
| 885 ASSERT(!data_->signal_sender_launched_); | 996 ASSERT(!IsActive()); |
| 886 delete data_; | 997 delete data_; |
| 887 } | 998 } |
| 888 | 999 |
| 889 | 1000 |
| 890 void Sampler::Start() { | 1001 void Sampler::Start() { |
| 891 // There can only be one active sampler at the time on POSIX | 1002 ASSERT(!IsActive()); |
| 892 // platforms. | 1003 SetActive(true); |
| 893 if (active_sampler_ != NULL) return; | 1004 SignalSender::AddActiveSampler(this); |
| 894 | |
| 895 // Request profiling signals. | |
| 896 struct sigaction sa; | |
| 897 sa.sa_sigaction = ProfilerSignalHandler; | |
| 898 sigemptyset(&sa.sa_mask); | |
| 899 sa.sa_flags = SA_RESTART | SA_SIGINFO; | |
| 900 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; | |
| 901 data_->signal_handler_installed_ = true; | |
| 902 | |
| 903 // Start a thread that sends SIGPROF signal to VM thread. | |
| 904 // Sending the signal ourselves instead of relying on itimer provides | |
| 905 // much better accuracy. | |
| 906 active_ = true; | |
| 907 if (pthread_create( | |
| 908 &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { | |
| 909 data_->signal_sender_launched_ = true; | |
| 910 } | |
| 911 | |
| 912 // Set this sampler as the active sampler. | |
| 913 active_sampler_ = this; | |
| 914 } | 1005 } |
| 915 | 1006 |
| 916 | 1007 |
| 917 void Sampler::Stop() { | 1008 void Sampler::Stop() { |
| 918 active_ = false; | 1009 ASSERT(IsActive()); |
| 919 | 1010 SignalSender::RemoveActiveSampler(this); |
| 920 // Wait for signal sender termination (it will exit after setting | 1011 SetActive(false); |
| 921 // active_ to false). | 1012 } |
| 922 if (data_->signal_sender_launched_) { | |
| 923 pthread_join(data_->signal_sender_thread_, NULL); | |
| 924 data_->signal_sender_launched_ = false; | |
| 925 } | |
| 926 | |
| 927 // Restore old signal handler | |
| 928 if (data_->signal_handler_installed_) { | |
| 929 sigaction(SIGPROF, &data_->old_signal_handler_, 0); | |
| 930 data_->signal_handler_installed_ = false; | |
| 931 } | |
| 932 | |
| 933 // This sampler is no longer the active sampler. | |
| 934 active_sampler_ = NULL; | |
| 935 } | |
| 936 | |
| 937 | 1013 |
| 938 #endif // ENABLE_LOGGING_AND_PROFILING | 1014 #endif // ENABLE_LOGGING_AND_PROFILING |
| 939 | 1015 |
| 940 } } // namespace v8::internal | 1016 } } // namespace v8::internal |
| OLD | NEW |