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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 #include <signal.h> // sigemptyset(), etc | 47 #include <signal.h> // sigemptyset(), etc |
48 #include <sys/regset.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-posix.h" | 55 #include "platform-posix.h" |
56 #include "platform.h" | 56 #include "platform.h" |
57 #include "simulator.h" | |
58 #include "v8threads.h" | 57 #include "v8threads.h" |
59 #include "vm-state-inl.h" | 58 #include "vm-state-inl.h" |
60 | 59 |
61 | 60 |
62 // It seems there is a bug in some Solaris distributions (experienced in | 61 // It seems there is a bug in some Solaris distributions (experienced in |
63 // SunOS 5.10 Generic_141445-09) which make it difficult or impossible to | 62 // SunOS 5.10 Generic_141445-09) which make it difficult or impossible to |
64 // access signbit() despite the availability of other C99 math functions. | 63 // access signbit() despite the availability of other C99 math functions. |
65 #ifndef signbit | 64 #ifndef signbit |
66 // Test sign - usually defined in math.h | 65 // Test sign - usually defined in math.h |
67 int signbit(double x) { | 66 int signbit(double x) { |
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
655 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. | 654 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. |
656 } | 655 } |
657 } | 656 } |
658 | 657 |
659 | 658 |
660 Semaphore* OS::CreateSemaphore(int count) { | 659 Semaphore* OS::CreateSemaphore(int count) { |
661 return new SolarisSemaphore(count); | 660 return new SolarisSemaphore(count); |
662 } | 661 } |
663 | 662 |
664 | 663 |
665 static pthread_t GetThreadID() { | |
666 return pthread_self(); | |
667 } | |
668 | |
669 | |
670 class Sampler::PlatformData : public Malloced { | |
671 public: | |
672 PlatformData() | |
673 : vm_tid_(GetThreadID()), | |
674 profiled_thread_id_(ThreadId::Current()) {} | |
675 | |
676 pthread_t vm_tid() const { return vm_tid_; } | |
677 ThreadId profiled_thread_id() { return profiled_thread_id_; } | |
678 | |
679 private: | |
680 pthread_t vm_tid_; | |
681 ThreadId profiled_thread_id_; | |
682 }; | |
683 | |
684 | |
685 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | |
686 USE(info); | |
687 if (signal != SIGPROF) return; | |
688 Isolate* isolate = Isolate::UncheckedCurrent(); | |
689 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { | |
690 // We require a fully initialized and entered isolate. | |
691 return; | |
692 } | |
693 if (v8::Locker::IsActive() && | |
694 !isolate->thread_manager()->IsLockedByCurrentThread()) { | |
695 return; | |
696 } | |
697 | |
698 Sampler* sampler = isolate->logger()->sampler(); | |
699 if (sampler == NULL || !sampler->IsActive()) return; | |
700 | |
701 TickSample sample_obj; | |
702 TickSample* sample = isolate->cpu_profiler()->TickSampleEvent(); | |
703 if (sample == NULL) sample = &sample_obj; | |
704 | |
705 #if defined(USE_SIMULATOR) | |
706 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS | |
707 ThreadId thread_id = sampler->platform_data()->profiled_thread_id(); | |
708 Isolate::PerIsolateThreadData* per_thread_data = isolate-> | |
709 FindPerThreadDataForThread(thread_id); | |
710 if (!per_thread_data) return; | |
711 Simulator* sim = per_thread_data->simulator(); | |
712 // Check if there is active simulator before allocating TickSample. | |
713 if (!sim) return; | |
714 #endif | |
715 #endif // USE_SIMULATOR | |
716 | |
717 // Extracting the sample from the context is extremely machine dependent. | |
718 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | |
719 mcontext_t& mcontext = ucontext->uc_mcontext; | |
720 sample->state = isolate->current_vm_state(); | |
721 | |
722 #if defined(USE_SIMULATOR) | |
723 #if V8_TARGET_ARCH_ARM | |
724 sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc)); | |
725 sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp)); | |
726 sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11)); | |
727 #elif V8_TARGET_ARCH_MIPS | |
728 sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc)); | |
729 sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp)); | |
730 sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp)); | |
731 #endif | |
732 #else | |
733 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); | |
734 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); | |
735 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); | |
736 #endif // USE_SIMULATOR | |
737 | |
738 sampler->SampleStack(sample); | |
739 sampler->Tick(sample); | |
740 } | |
741 | |
742 | |
743 class SignalSender : public Thread { | |
744 public: | |
745 static const int kSignalSenderStackSize = 64 * KB; | |
746 | |
747 explicit SignalSender(int interval) | |
748 : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)), | |
749 interval_(interval) {} | |
750 | |
751 static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } | |
752 static void TearDown() { delete mutex_; } | |
753 | |
754 static void InstallSignalHandler() { | |
755 struct sigaction sa; | |
756 sa.sa_sigaction = ProfilerSignalHandler; | |
757 sigemptyset(&sa.sa_mask); | |
758 sa.sa_flags = SA_RESTART | SA_SIGINFO; | |
759 signal_handler_installed_ = | |
760 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); | |
761 } | |
762 | |
763 static void RestoreSignalHandler() { | |
764 if (signal_handler_installed_) { | |
765 sigaction(SIGPROF, &old_signal_handler_, 0); | |
766 signal_handler_installed_ = false; | |
767 } | |
768 } | |
769 | |
770 static void AddActiveSampler(Sampler* sampler) { | |
771 ScopedLock lock(mutex_); | |
772 SamplerRegistry::AddActiveSampler(sampler); | |
773 if (instance_ == NULL) { | |
774 // Start a thread that will send SIGPROF signal to VM threads, | |
775 // when CPU profiling will be enabled. | |
776 instance_ = new SignalSender(sampler->interval()); | |
777 instance_->StartSynchronously(); | |
778 } else { | |
779 ASSERT(instance_->interval_ == sampler->interval()); | |
780 } | |
781 } | |
782 | |
783 static void RemoveActiveSampler(Sampler* sampler) { | |
784 ScopedLock lock(mutex_); | |
785 SamplerRegistry::RemoveActiveSampler(sampler); | |
786 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { | |
787 instance_->Join(); | |
788 delete instance_; | |
789 instance_ = NULL; | |
790 RestoreSignalHandler(); | |
791 } | |
792 } | |
793 | |
794 // Implement Thread::Run(). | |
795 virtual void Run() { | |
796 SamplerRegistry::State state; | |
797 while ((state = SamplerRegistry::GetState()) != | |
798 SamplerRegistry::HAS_NO_SAMPLERS) { | |
799 // When CPU profiling is enabled both JavaScript and C++ code is | |
800 // profiled. We must not suspend. | |
801 if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { | |
802 if (!signal_handler_installed_) InstallSignalHandler(); | |
803 SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); | |
804 } else if (signal_handler_installed_) { | |
805 RestoreSignalHandler(); | |
806 } | |
807 Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough. | |
808 } | |
809 } | |
810 | |
811 static void DoCpuProfile(Sampler* sampler, void* raw_sender) { | |
812 if (!sampler->IsProfiling()) return; | |
813 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender); | |
814 sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); | |
815 } | |
816 | |
817 void SendProfilingSignal(pthread_t tid) { | |
818 if (!signal_handler_installed_) return; | |
819 pthread_kill(tid, SIGPROF); | |
820 } | |
821 | |
822 void Sleep() { | |
823 // Convert ms to us and subtract 100 us to compensate delays | |
824 // occuring during signal delivery. | |
825 useconds_t interval = interval_ * 1000 - 100; | |
826 int result = usleep(interval); | |
827 #ifdef DEBUG | |
828 if (result != 0 && errno != EINTR) { | |
829 fprintf(stderr, | |
830 "SignalSender usleep error; interval = %u, errno = %d\n", | |
831 interval, | |
832 errno); | |
833 ASSERT(result == 0 || errno == EINTR); | |
834 } | |
835 #endif | |
836 USE(result); | |
837 } | |
838 | |
839 const int interval_; | |
840 | |
841 // Protects the process wide state below. | |
842 static Mutex* mutex_; | |
843 static SignalSender* instance_; | |
844 static bool signal_handler_installed_; | |
845 static struct sigaction old_signal_handler_; | |
846 | |
847 private: | |
848 DISALLOW_COPY_AND_ASSIGN(SignalSender); | |
849 }; | |
850 | |
851 Mutex* SignalSender::mutex_ = NULL; | |
852 SignalSender* SignalSender::instance_ = NULL; | |
853 struct sigaction SignalSender::old_signal_handler_; | |
854 bool SignalSender::signal_handler_installed_ = false; | |
855 | |
856 | |
857 void OS::SetUp() { | 664 void OS::SetUp() { |
858 // Seed the random number generator. | 665 // Seed the random number generator. |
859 // Convert the current time to a 64-bit integer first, before converting it | 666 // Convert the current time to a 64-bit integer first, before converting it |
860 // to an unsigned. Going directly will cause an overflow and the seed to be | 667 // to an unsigned. Going directly will cause an overflow and the seed to be |
861 // set to all ones. The seed will be identical for different instances that | 668 // set to all ones. The seed will be identical for different instances that |
862 // call this setup code within the same millisecond. | 669 // call this setup code within the same millisecond. |
863 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); | 670 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); |
864 srandom(static_cast<unsigned int>(seed)); | 671 srandom(static_cast<unsigned int>(seed)); |
865 limit_mutex = CreateMutex(); | 672 limit_mutex = CreateMutex(); |
866 SignalSender::SetUp(); | |
867 } | 673 } |
868 | 674 |
869 | 675 |
870 void OS::TearDown() { | 676 void OS::TearDown() { |
871 SignalSender::TearDown(); | |
872 delete limit_mutex; | 677 delete limit_mutex; |
873 } | 678 } |
874 | 679 |
875 | 680 |
876 Sampler::Sampler(Isolate* isolate, int interval) | |
877 : isolate_(isolate), | |
878 interval_(interval), | |
879 profiling_(false), | |
880 active_(false), | |
881 samples_taken_(0) { | |
882 data_ = new PlatformData; | |
883 } | |
884 | |
885 | |
886 Sampler::~Sampler() { | |
887 ASSERT(!IsActive()); | |
888 delete data_; | |
889 } | |
890 | |
891 | |
892 void Sampler::Start() { | |
893 ASSERT(!IsActive()); | |
894 SetActive(true); | |
895 SignalSender::AddActiveSampler(this); | |
896 } | |
897 | |
898 | |
899 void Sampler::Stop() { | |
900 ASSERT(IsActive()); | |
901 SignalSender::RemoveActiveSampler(this); | |
902 SetActive(false); | |
903 } | |
904 | |
905 } } // namespace v8::internal | 681 } } // namespace v8::internal |
OLD | NEW |