OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 #include <strings.h> // index | 46 #include <strings.h> // index |
47 #include <errno.h> | 47 #include <errno.h> |
48 #include <stdarg.h> | 48 #include <stdarg.h> |
49 | 49 |
50 #undef MAP_TYPE | 50 #undef MAP_TYPE |
51 | 51 |
52 #include "v8.h" | 52 #include "v8.h" |
53 | 53 |
54 #include "platform-posix.h" | 54 #include "platform-posix.h" |
55 #include "platform.h" | 55 #include "platform.h" |
56 #include "simulator.h" | |
57 #include "v8threads.h" | 56 #include "v8threads.h" |
58 #include "vm-state-inl.h" | 57 #include "vm-state-inl.h" |
59 | 58 |
60 | 59 |
61 namespace v8 { | 60 namespace v8 { |
62 namespace internal { | 61 namespace internal { |
63 | 62 |
64 // 0 is never a valid thread id on Linux and OpenBSD since tids and pids share a | 63 // 0 is never a valid thread id on Linux and OpenBSD since tids and pids share a |
65 // name space and pid 0 is reserved (see man 2 kill). | 64 // name space and pid 0 is reserved (see man 2 kill). |
66 static const pthread_t kNoThread = (pthread_t) 0; | 65 static const pthread_t kNoThread = (pthread_t) 0; |
(...skipping 655 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
722 usleep(ts.tv_nsec / 1000); | 721 usleep(ts.tv_nsec / 1000); |
723 to--; | 722 to--; |
724 } | 723 } |
725 } | 724 } |
726 | 725 |
727 Semaphore* OS::CreateSemaphore(int count) { | 726 Semaphore* OS::CreateSemaphore(int count) { |
728 return new OpenBSDSemaphore(count); | 727 return new OpenBSDSemaphore(count); |
729 } | 728 } |
730 | 729 |
731 | 730 |
732 static pthread_t GetThreadID() { | |
733 return pthread_self(); | |
734 } | |
735 | |
736 | |
737 class Sampler::PlatformData : public Malloced { | |
738 public: | |
739 PlatformData() | |
740 : vm_tid_(GetThreadID()), | |
741 profiled_thread_id_(ThreadId::Current()) {} | |
742 | |
743 pthread_t vm_tid() const { return vm_tid_; } | |
744 ThreadId profiled_thread_id() { return profiled_thread_id_; } | |
745 | |
746 private: | |
747 pthread_t vm_tid_; | |
748 ThreadId profiled_thread_id_; | |
749 }; | |
750 | |
751 | |
752 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | |
753 USE(info); | |
754 if (signal != SIGPROF) return; | |
755 Isolate* isolate = Isolate::UncheckedCurrent(); | |
756 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { | |
757 // We require a fully initialized and entered isolate. | |
758 return; | |
759 } | |
760 if (v8::Locker::IsActive() && | |
761 !isolate->thread_manager()->IsLockedByCurrentThread()) { | |
762 return; | |
763 } | |
764 | |
765 Sampler* sampler = isolate->logger()->sampler(); | |
766 if (sampler == NULL || !sampler->IsActive()) return; | |
767 | |
768 #if defined(USE_SIMULATOR) | |
769 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS | |
770 ThreadId thread_id = sampler->platform_data()->profiled_thread_id(); | |
771 Isolate::PerIsolateThreadData* per_thread_data = isolate-> | |
772 FindPerThreadDataForThread(thread_id); | |
773 if (!per_thread_data) return; | |
774 Simulator* sim = per_thread_data->simulator(); | |
775 // Check if there is active simulator before allocating TickSample. | |
776 if (!sim) return; | |
777 #endif | |
778 #endif // USE_SIMULATOR | |
779 | |
780 TickSample sample_obj; | |
781 TickSample* sample = isolate->cpu_profiler()->TickSampleEvent(); | |
782 if (sample == NULL) sample = &sample_obj; | |
783 | |
784 // Extracting the sample from the context is extremely machine dependent. | |
785 sample->state = isolate->current_vm_state(); | |
786 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | |
787 #if defined(USE_SIMULATOR) | |
788 #if V8_TARGET_ARCH_ARM | |
789 sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc)); | |
790 sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp)); | |
791 sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11)); | |
792 #elif V8_TARGET_ARCH_MIPS | |
793 sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc)); | |
794 sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp)); | |
795 sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp)); | |
796 #endif | |
797 #else | |
798 #ifdef __NetBSD__ | |
799 mcontext_t& mcontext = ucontext->uc_mcontext; | |
800 #if V8_HOST_ARCH_IA32 | |
801 sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]); | |
802 sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]); | |
803 sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]); | |
804 #elif V8_HOST_ARCH_X64 | |
805 sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]); | |
806 sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]); | |
807 sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]); | |
808 #endif // V8_HOST_ARCH | |
809 #else // OpenBSD | |
810 #if V8_HOST_ARCH_IA32 | |
811 sample->pc = reinterpret_cast<Address>(ucontext->sc_eip); | |
812 sample->sp = reinterpret_cast<Address>(ucontext->sc_esp); | |
813 sample->fp = reinterpret_cast<Address>(ucontext->sc_ebp); | |
814 #elif V8_HOST_ARCH_X64 | |
815 sample->pc = reinterpret_cast<Address>(ucontext->sc_rip); | |
816 sample->sp = reinterpret_cast<Address>(ucontext->sc_rsp); | |
817 sample->fp = reinterpret_cast<Address>(ucontext->sc_rbp); | |
818 #endif // V8_HOST_ARCH | |
819 #endif // __NetBSD__ | |
820 #endif // USE_SIMULATOR | |
821 sampler->SampleStack(sample); | |
822 sampler->Tick(sample); | |
823 } | |
824 | |
825 | |
826 class SignalSender : public Thread { | |
827 public: | |
828 static const int kSignalSenderStackSize = 64 * KB; | |
829 | |
830 explicit SignalSender(int interval) | |
831 : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)), | |
832 vm_tgid_(getpid()), | |
833 interval_(interval) {} | |
834 | |
835 static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } | |
836 static void TearDown() { delete mutex_; } | |
837 | |
838 static void InstallSignalHandler() { | |
839 struct sigaction sa; | |
840 sa.sa_sigaction = ProfilerSignalHandler; | |
841 sigemptyset(&sa.sa_mask); | |
842 sa.sa_flags = SA_RESTART | SA_SIGINFO; | |
843 signal_handler_installed_ = | |
844 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); | |
845 } | |
846 | |
847 static void RestoreSignalHandler() { | |
848 if (signal_handler_installed_) { | |
849 sigaction(SIGPROF, &old_signal_handler_, 0); | |
850 signal_handler_installed_ = false; | |
851 } | |
852 } | |
853 | |
854 static void AddActiveSampler(Sampler* sampler) { | |
855 ScopedLock lock(mutex_); | |
856 SamplerRegistry::AddActiveSampler(sampler); | |
857 if (instance_ == NULL) { | |
858 // Start a thread that will send SIGPROF signal to VM threads, | |
859 // when CPU profiling will be enabled. | |
860 instance_ = new SignalSender(sampler->interval()); | |
861 instance_->StartSynchronously(); | |
862 } else { | |
863 ASSERT(instance_->interval_ == sampler->interval()); | |
864 } | |
865 } | |
866 | |
867 static void RemoveActiveSampler(Sampler* sampler) { | |
868 ScopedLock lock(mutex_); | |
869 SamplerRegistry::RemoveActiveSampler(sampler); | |
870 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { | |
871 instance_->Join(); | |
872 delete instance_; | |
873 instance_ = NULL; | |
874 RestoreSignalHandler(); | |
875 } | |
876 } | |
877 | |
878 // Implement Thread::Run(). | |
879 virtual void Run() { | |
880 SamplerRegistry::State state; | |
881 while ((state = SamplerRegistry::GetState()) != | |
882 SamplerRegistry::HAS_NO_SAMPLERS) { | |
883 // When CPU profiling is enabled both JavaScript and C++ code is | |
884 // profiled. We must not suspend. | |
885 if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { | |
886 if (!signal_handler_installed_) InstallSignalHandler(); | |
887 SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); | |
888 } else if (signal_handler_installed_) { | |
889 RestoreSignalHandler(); | |
890 } | |
891 Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough. | |
892 } | |
893 } | |
894 | |
895 static void DoCpuProfile(Sampler* sampler, void* raw_sender) { | |
896 if (!sampler->IsProfiling()) return; | |
897 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender); | |
898 sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); | |
899 } | |
900 | |
901 void SendProfilingSignal(pthread_t tid) { | |
902 if (!signal_handler_installed_) return; | |
903 pthread_kill(tid, SIGPROF); | |
904 } | |
905 | |
906 void Sleep() { | |
907 // Convert ms to us and subtract 100 us to compensate delays | |
908 // occuring during signal delivery. | |
909 useconds_t interval = interval_ * 1000 - 100; | |
910 int result = usleep(interval); | |
911 #ifdef DEBUG | |
912 if (result != 0 && errno != EINTR) { | |
913 fprintf(stderr, | |
914 "SignalSender usleep error; interval = %u, errno = %d\n", | |
915 interval, | |
916 errno); | |
917 ASSERT(result == 0 || errno == EINTR); | |
918 } | |
919 #endif | |
920 USE(result); | |
921 } | |
922 | |
923 const int vm_tgid_; | |
924 const int interval_; | |
925 | |
926 // Protects the process wide state below. | |
927 static Mutex* mutex_; | |
928 static SignalSender* instance_; | |
929 static bool signal_handler_installed_; | |
930 static struct sigaction old_signal_handler_; | |
931 | |
932 private: | |
933 DISALLOW_COPY_AND_ASSIGN(SignalSender); | |
934 }; | |
935 | |
936 | |
937 Mutex* SignalSender::mutex_ = NULL; | |
938 SignalSender* SignalSender::instance_ = NULL; | |
939 struct sigaction SignalSender::old_signal_handler_; | |
940 bool SignalSender::signal_handler_installed_ = false; | |
941 | |
942 | |
943 void OS::SetUp() { | 731 void OS::SetUp() { |
944 // Seed the random number generator. We preserve microsecond resolution. | 732 // Seed the random number generator. We preserve microsecond resolution. |
945 uint64_t seed = Ticks() ^ (getpid() << 16); | 733 uint64_t seed = Ticks() ^ (getpid() << 16); |
946 srandom(static_cast<unsigned int>(seed)); | 734 srandom(static_cast<unsigned int>(seed)); |
947 limit_mutex = CreateMutex(); | 735 limit_mutex = CreateMutex(); |
948 SignalSender::SetUp(); | |
949 } | 736 } |
950 | 737 |
951 | 738 |
952 void OS::TearDown() { | 739 void OS::TearDown() { |
953 SignalSender::TearDown(); | |
954 delete limit_mutex; | 740 delete limit_mutex; |
955 } | 741 } |
956 | 742 |
957 | 743 |
958 Sampler::Sampler(Isolate* isolate, int interval) | |
959 : isolate_(isolate), | |
960 interval_(interval), | |
961 profiling_(false), | |
962 active_(false), | |
963 samples_taken_(0) { | |
964 data_ = new PlatformData; | |
965 } | |
966 | |
967 | |
968 Sampler::~Sampler() { | |
969 ASSERT(!IsActive()); | |
970 delete data_; | |
971 } | |
972 | |
973 | |
974 void Sampler::Start() { | |
975 ASSERT(!IsActive()); | |
976 SetActive(true); | |
977 SignalSender::AddActiveSampler(this); | |
978 } | |
979 | |
980 | |
981 void Sampler::Stop() { | |
982 ASSERT(IsActive()); | |
983 SignalSender::RemoveActiveSampler(this); | |
984 SetActive(false); | |
985 } | |
986 | |
987 | |
988 } } // namespace v8::internal | 744 } } // namespace v8::internal |
OLD | NEW |