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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 #include <stdarg.h> | 49 #include <stdarg.h> |
50 #include <limits.h> | 50 #include <limits.h> |
51 | 51 |
52 #undef MAP_TYPE | 52 #undef MAP_TYPE |
53 | 53 |
54 #include "v8.h" | 54 #include "v8.h" |
55 #include "v8threads.h" | 55 #include "v8threads.h" |
56 | 56 |
57 #include "platform-posix.h" | 57 #include "platform-posix.h" |
58 #include "platform.h" | 58 #include "platform.h" |
59 #include "simulator.h" | |
60 #include "vm-state-inl.h" | 59 #include "vm-state-inl.h" |
61 | 60 |
62 | 61 |
63 namespace v8 { | 62 namespace v8 { |
64 namespace internal { | 63 namespace internal { |
65 | 64 |
66 // 0 is never a valid thread id on FreeBSD since tids and pids share a | 65 // 0 is never a valid thread id on FreeBSD since tids and pids share a |
67 // name space and pid 0 is used to kill the group (see man 2 kill). | 66 // name space and pid 0 is used to kill the group (see man 2 kill). |
68 static const pthread_t kNoThread = (pthread_t) 0; | 67 static const pthread_t kNoThread = (pthread_t) 0; |
69 | 68 |
(...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
676 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. | 675 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. |
677 } | 676 } |
678 } | 677 } |
679 | 678 |
680 | 679 |
681 Semaphore* OS::CreateSemaphore(int count) { | 680 Semaphore* OS::CreateSemaphore(int count) { |
682 return new FreeBSDSemaphore(count); | 681 return new FreeBSDSemaphore(count); |
683 } | 682 } |
684 | 683 |
685 | 684 |
686 static pthread_t GetThreadID() { | |
687 pthread_t thread_id = pthread_self(); | |
688 return thread_id; | |
689 } | |
690 | |
691 | |
692 class Sampler::PlatformData : public Malloced { | |
693 public: | |
694 PlatformData() | |
695 : vm_tid_(GetThreadID()), | |
696 profiled_thread_id_(ThreadId::Current()) {} | |
697 | |
698 pthread_t vm_tid() const { return vm_tid_; } | |
699 ThreadId profiled_thread_id() { return profiled_thread_id_; } | |
700 | |
701 private: | |
702 pthread_t vm_tid_; | |
703 ThreadId profiled_thread_id_; | |
704 }; | |
705 | |
706 | |
707 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | |
708 USE(info); | |
709 if (signal != SIGPROF) return; | |
710 Isolate* isolate = Isolate::UncheckedCurrent(); | |
711 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { | |
712 // We require a fully initialized and entered isolate. | |
713 return; | |
714 } | |
715 if (v8::Locker::IsActive() && | |
716 !isolate->thread_manager()->IsLockedByCurrentThread()) { | |
717 return; | |
718 } | |
719 | |
720 Sampler* sampler = isolate->logger()->sampler(); | |
721 if (sampler == NULL || !sampler->IsActive()) return; | |
722 | |
723 #if defined(USE_SIMULATOR) | |
724 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS | |
725 ThreadId thread_id = sampler->platform_data()->profiled_thread_id(); | |
726 Isolate::PerIsolateThreadData* per_thread_data = isolate-> | |
727 FindPerThreadDataForThread(thread_id); | |
728 if (!per_thread_data) return; | |
729 Simulator* sim = per_thread_data->simulator(); | |
730 // Check if there is active simulator before allocating TickSample. | |
731 if (!sim) return; | |
732 #endif | |
733 #endif // USE_SIMULATOR | |
734 | |
735 TickSample sample_obj; | |
736 TickSample* sample = isolate->cpu_profiler()->TickSampleEvent(); | |
737 if (sample == NULL) sample = &sample_obj; | |
738 | |
739 // Extracting the sample from the context is extremely machine dependent. | |
740 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | |
741 mcontext_t& mcontext = ucontext->uc_mcontext; | |
742 sample->state = isolate->current_vm_state(); | |
743 #if defined(USE_SIMULATOR) | |
744 #if V8_TARGET_ARCH_ARM | |
745 sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc)); | |
746 sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp)); | |
747 sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11)); | |
748 #elif V8_TARGET_ARCH_MIPS | |
749 sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc)); | |
750 sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp)); | |
751 sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp)); | |
752 #endif | |
753 #else | |
754 #if V8_HOST_ARCH_IA32 | |
755 sample->pc = reinterpret_cast<Address>(mcontext.mc_eip); | |
756 sample->sp = reinterpret_cast<Address>(mcontext.mc_esp); | |
757 sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp); | |
758 #elif V8_HOST_ARCH_X64 | |
759 sample->pc = reinterpret_cast<Address>(mcontext.mc_rip); | |
760 sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp); | |
761 sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp); | |
762 #elif V8_HOST_ARCH_ARM | |
763 sample->pc = reinterpret_cast<Address>(mcontext.mc_r15); | |
764 sample->sp = reinterpret_cast<Address>(mcontext.mc_r13); | |
765 sample->fp = reinterpret_cast<Address>(mcontext.mc_r11); | |
766 #endif // V8_HOST_ARCH_* | |
767 #endif // USE_SIMULATOR | |
768 sampler->SampleStack(sample); | |
769 sampler->Tick(sample); | |
770 } | |
771 | |
772 | |
773 class SignalSender : public Thread { | |
774 public: | |
775 static const int kSignalSenderStackSize = 64 * KB; | |
776 | |
777 explicit SignalSender(int interval) | |
778 : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)), | |
779 interval_(interval) {} | |
780 | |
781 static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } | |
782 static void TearDown() { delete mutex_; } | |
783 | |
784 static void AddActiveSampler(Sampler* sampler) { | |
785 ScopedLock lock(mutex_); | |
786 SamplerRegistry::AddActiveSampler(sampler); | |
787 if (instance_ == NULL) { | |
788 // Install a signal handler. | |
789 struct sigaction sa; | |
790 sa.sa_sigaction = ProfilerSignalHandler; | |
791 sigemptyset(&sa.sa_mask); | |
792 sa.sa_flags = SA_RESTART | SA_SIGINFO; | |
793 signal_handler_installed_ = | |
794 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); | |
795 | |
796 // Start a thread that sends SIGPROF signal to VM threads. | |
797 instance_ = new SignalSender(sampler->interval()); | |
798 instance_->StartSynchronously(); | |
799 } else { | |
800 ASSERT(instance_->interval_ == sampler->interval()); | |
801 } | |
802 } | |
803 | |
804 static void RemoveActiveSampler(Sampler* sampler) { | |
805 ScopedLock lock(mutex_); | |
806 SamplerRegistry::RemoveActiveSampler(sampler); | |
807 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { | |
808 instance_->Join(); | |
809 delete instance_; | |
810 instance_ = NULL; | |
811 | |
812 // Restore the old signal handler. | |
813 if (signal_handler_installed_) { | |
814 sigaction(SIGPROF, &old_signal_handler_, 0); | |
815 signal_handler_installed_ = false; | |
816 } | |
817 } | |
818 } | |
819 | |
820 // Implement Thread::Run(). | |
821 virtual void Run() { | |
822 SamplerRegistry::State state; | |
823 while ((state = SamplerRegistry::GetState()) != | |
824 SamplerRegistry::HAS_NO_SAMPLERS) { | |
825 // When CPU profiling is enabled both JavaScript and C++ code is | |
826 // profiled. We must not suspend. | |
827 if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { | |
828 SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); | |
829 } | |
830 Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough. | |
831 } | |
832 } | |
833 | |
834 static void DoCpuProfile(Sampler* sampler, void* raw_sender) { | |
835 if (!sampler->IsProfiling()) return; | |
836 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender); | |
837 sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); | |
838 } | |
839 | |
840 void SendProfilingSignal(pthread_t tid) { | |
841 if (!signal_handler_installed_) return; | |
842 pthread_kill(tid, SIGPROF); | |
843 } | |
844 | |
845 void Sleep() { | |
846 // Convert ms to us and subtract 100 us to compensate delays | |
847 // occuring during signal delivery. | |
848 useconds_t interval = interval_ * 1000 - 100; | |
849 int result = usleep(interval); | |
850 #ifdef DEBUG | |
851 if (result != 0 && errno != EINTR) { | |
852 fprintf(stderr, | |
853 "SignalSender usleep error; interval = %u, errno = %d\n", | |
854 interval, | |
855 errno); | |
856 ASSERT(result == 0 || errno == EINTR); | |
857 } | |
858 #endif | |
859 USE(result); | |
860 } | |
861 | |
862 const int interval_; | |
863 | |
864 // Protects the process wide state below. | |
865 static Mutex* mutex_; | |
866 static SignalSender* instance_; | |
867 static bool signal_handler_installed_; | |
868 static struct sigaction old_signal_handler_; | |
869 | |
870 private: | |
871 DISALLOW_COPY_AND_ASSIGN(SignalSender); | |
872 }; | |
873 | |
874 Mutex* SignalSender::mutex_ = NULL; | |
875 SignalSender* SignalSender::instance_ = NULL; | |
876 struct sigaction SignalSender::old_signal_handler_; | |
877 bool SignalSender::signal_handler_installed_ = false; | |
878 | |
879 | |
880 void OS::SetUp() { | 685 void OS::SetUp() { |
881 // Seed the random number generator. | 686 // Seed the random number generator. |
882 // Convert the current time to a 64-bit integer first, before converting it | 687 // Convert the current time to a 64-bit integer first, before converting it |
883 // to an unsigned. Going directly can cause an overflow and the seed to be | 688 // to an unsigned. Going directly can cause an overflow and the seed to be |
884 // set to all ones. The seed will be identical for different instances that | 689 // set to all ones. The seed will be identical for different instances that |
885 // call this setup code within the same millisecond. | 690 // call this setup code within the same millisecond. |
886 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); | 691 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); |
887 srandom(static_cast<unsigned int>(seed)); | 692 srandom(static_cast<unsigned int>(seed)); |
888 limit_mutex = CreateMutex(); | 693 limit_mutex = CreateMutex(); |
889 SignalSender::SetUp(); | |
890 } | 694 } |
891 | 695 |
892 | 696 |
893 void OS::TearDown() { | 697 void OS::TearDown() { |
894 SignalSender::TearDown(); | |
895 delete limit_mutex; | 698 delete limit_mutex; |
896 } | 699 } |
897 | 700 |
898 | 701 |
899 Sampler::Sampler(Isolate* isolate, int interval) | |
900 : isolate_(isolate), | |
901 interval_(interval), | |
902 profiling_(false), | |
903 active_(false), | |
904 samples_taken_(0) { | |
905 data_ = new PlatformData; | |
906 } | |
907 | |
908 | |
909 Sampler::~Sampler() { | |
910 ASSERT(!IsActive()); | |
911 delete data_; | |
912 } | |
913 | |
914 | |
915 void Sampler::Start() { | |
916 ASSERT(!IsActive()); | |
917 SetActive(true); | |
918 SignalSender::AddActiveSampler(this); | |
919 } | |
920 | |
921 | |
922 void Sampler::Stop() { | |
923 ASSERT(IsActive()); | |
924 SignalSender::RemoveActiveSampler(this); | |
925 SetActive(false); | |
926 } | |
927 | |
928 | |
929 } } // namespace v8::internal | 702 } } // namespace v8::internal |
OLD | NEW |