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 725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 ts.tv_nsec = (timeout % 1000000) * 1000; | 736 ts.tv_nsec = (timeout % 1000000) * 1000; |
737 return semaphore_timedwait(semaphore_, ts) != KERN_OPERATION_TIMED_OUT; | 737 return semaphore_timedwait(semaphore_, ts) != KERN_OPERATION_TIMED_OUT; |
738 } | 738 } |
739 | 739 |
740 | 740 |
741 Semaphore* OS::CreateSemaphore(int count) { | 741 Semaphore* OS::CreateSemaphore(int count) { |
742 return new MacOSSemaphore(count); | 742 return new MacOSSemaphore(count); |
743 } | 743 } |
744 | 744 |
745 | 745 |
746 class Sampler::PlatformData : public Malloced { | |
747 public: | |
748 PlatformData() | |
749 : profiled_thread_(mach_thread_self()), | |
750 profiled_thread_id_(ThreadId::Current()) {} | |
751 | |
752 ~PlatformData() { | |
753 // Deallocate Mach port for thread. | |
754 mach_port_deallocate(mach_task_self(), profiled_thread_); | |
755 } | |
756 | |
757 thread_act_t profiled_thread() { return profiled_thread_; } | |
758 ThreadId profiled_thread_id() { return profiled_thread_id_; } | |
759 | |
760 private: | |
761 // Note: for profiled_thread_ Mach primitives are used instead of PThread's | |
762 // because the latter doesn't provide thread manipulation primitives required. | |
763 // For details, consult "Mac OS X Internals" book, Section 7.3. | |
764 thread_act_t profiled_thread_; | |
765 ThreadId profiled_thread_id_; | |
766 }; | |
767 | |
768 | |
769 class SamplerThread : public Thread { | |
770 public: | |
771 static const int kSamplerThreadStackSize = 64 * KB; | |
772 | |
773 explicit SamplerThread(int interval) | |
774 : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)), | |
775 interval_(interval) {} | |
776 | |
777 static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } | |
778 static void TearDown() { delete mutex_; } | |
779 | |
780 static void AddActiveSampler(Sampler* sampler) { | |
781 ScopedLock lock(mutex_); | |
782 SamplerRegistry::AddActiveSampler(sampler); | |
783 if (instance_ == NULL) { | |
784 instance_ = new SamplerThread(sampler->interval()); | |
785 instance_->StartSynchronously(); | |
786 } else { | |
787 ASSERT(instance_->interval_ == sampler->interval()); | |
788 } | |
789 } | |
790 | |
791 static void RemoveActiveSampler(Sampler* sampler) { | |
792 ScopedLock lock(mutex_); | |
793 SamplerRegistry::RemoveActiveSampler(sampler); | |
794 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { | |
795 instance_->Join(); | |
796 delete instance_; | |
797 instance_ = NULL; | |
798 } | |
799 } | |
800 | |
801 // Implement Thread::Run(). | |
802 virtual void Run() { | |
803 SamplerRegistry::State state; | |
804 while ((state = SamplerRegistry::GetState()) != | |
805 SamplerRegistry::HAS_NO_SAMPLERS) { | |
806 // When CPU profiling is enabled both JavaScript and C++ code is | |
807 // profiled. We must not suspend. | |
808 if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { | |
809 SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); | |
810 } | |
811 OS::Sleep(interval_); | |
812 } | |
813 } | |
814 | |
815 static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) { | |
816 if (!sampler->isolate()->IsInitialized()) return; | |
817 if (!sampler->IsProfiling()) return; | |
818 SamplerThread* sampler_thread = | |
819 reinterpret_cast<SamplerThread*>(raw_sampler_thread); | |
820 sampler_thread->SampleContext(sampler); | |
821 } | |
822 | |
823 void SampleContext(Sampler* sampler) { | |
824 thread_act_t profiled_thread = sampler->platform_data()->profiled_thread(); | |
825 Isolate* isolate = sampler->isolate(); | |
826 #if defined(USE_SIMULATOR) | |
827 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS | |
828 ThreadId thread_id = sampler->platform_data()->profiled_thread_id(); | |
829 Isolate::PerIsolateThreadData* per_thread_data = isolate-> | |
830 FindPerThreadDataForThread(thread_id); | |
831 if (!per_thread_data) return; | |
832 Simulator* sim = per_thread_data->simulator(); | |
833 // Check if there is active simulator before allocating TickSample. | |
834 if (!sim) return; | |
835 #endif | |
836 #endif // USE_SIMULATOR | |
837 TickSample sample_obj; | |
838 TickSample* sample = isolate->cpu_profiler()->TickSampleEvent(); | |
839 if (sample == NULL) sample = &sample_obj; | |
840 | |
841 if (KERN_SUCCESS != thread_suspend(profiled_thread)) return; | |
842 | |
843 #if V8_HOST_ARCH_X64 | |
844 thread_state_flavor_t flavor = x86_THREAD_STATE64; | |
845 x86_thread_state64_t state; | |
846 mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; | |
847 #if __DARWIN_UNIX03 | |
848 #define REGISTER_FIELD(name) __r ## name | |
849 #else | |
850 #define REGISTER_FIELD(name) r ## name | |
851 #endif // __DARWIN_UNIX03 | |
852 #elif V8_HOST_ARCH_IA32 | |
853 thread_state_flavor_t flavor = i386_THREAD_STATE; | |
854 i386_thread_state_t state; | |
855 mach_msg_type_number_t count = i386_THREAD_STATE_COUNT; | |
856 #if __DARWIN_UNIX03 | |
857 #define REGISTER_FIELD(name) __e ## name | |
858 #else | |
859 #define REGISTER_FIELD(name) e ## name | |
860 #endif // __DARWIN_UNIX03 | |
861 #else | |
862 #error Unsupported Mac OS X host architecture. | |
863 #endif // V8_HOST_ARCH | |
864 | |
865 if (thread_get_state(profiled_thread, | |
866 flavor, | |
867 reinterpret_cast<natural_t*>(&state), | |
868 &count) == KERN_SUCCESS) { | |
869 sample->state = isolate->current_vm_state(); | |
870 #if defined(USE_SIMULATOR) | |
871 #if V8_TARGET_ARCH_ARM | |
872 sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc)); | |
873 sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp)); | |
874 sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11)); | |
875 #elif V8_TARGET_ARCH_MIPS | |
876 sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc)); | |
877 sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp)); | |
878 sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp)); | |
879 #endif | |
880 #else | |
881 sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip)); | |
882 sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp)); | |
883 sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp)); | |
884 #endif // USE_SIMULATOR | |
885 sampler->SampleStack(sample); | |
886 sampler->Tick(sample); | |
887 } | |
888 thread_resume(profiled_thread); | |
889 } | |
890 | |
891 const int interval_; | |
892 | |
893 // Protects the process wide state below. | |
894 static Mutex* mutex_; | |
895 static SamplerThread* instance_; | |
896 | |
897 private: | |
898 DISALLOW_COPY_AND_ASSIGN(SamplerThread); | |
899 }; | |
900 | |
901 #undef REGISTER_FIELD | |
902 | |
903 | |
904 Mutex* SamplerThread::mutex_ = NULL; | |
905 SamplerThread* SamplerThread::instance_ = NULL; | |
906 | |
907 | |
908 void OS::SetUp() { | 746 void OS::SetUp() { |
909 // Seed the random number generator. We preserve microsecond resolution. | 747 // Seed the random number generator. We preserve microsecond resolution. |
910 uint64_t seed = Ticks() ^ (getpid() << 16); | 748 uint64_t seed = Ticks() ^ (getpid() << 16); |
911 srandom(static_cast<unsigned int>(seed)); | 749 srandom(static_cast<unsigned int>(seed)); |
912 limit_mutex = CreateMutex(); | 750 limit_mutex = CreateMutex(); |
913 SamplerThread::SetUp(); | |
914 } | 751 } |
915 | 752 |
916 | 753 |
917 void OS::TearDown() { | 754 void OS::TearDown() { |
918 SamplerThread::TearDown(); | |
919 delete limit_mutex; | 755 delete limit_mutex; |
920 } | 756 } |
921 | 757 |
922 | 758 |
923 Sampler::Sampler(Isolate* isolate, int interval) | |
924 : isolate_(isolate), | |
925 interval_(interval), | |
926 profiling_(false), | |
927 active_(false), | |
928 samples_taken_(0) { | |
929 data_ = new PlatformData; | |
930 } | |
931 | |
932 | |
933 Sampler::~Sampler() { | |
934 ASSERT(!IsActive()); | |
935 delete data_; | |
936 } | |
937 | |
938 | |
939 void Sampler::Start() { | |
940 ASSERT(!IsActive()); | |
941 SetActive(true); | |
942 SamplerThread::AddActiveSampler(this); | |
943 } | |
944 | |
945 | |
946 void Sampler::Stop() { | |
947 ASSERT(IsActive()); | |
948 SamplerThread::RemoveActiveSampler(this); | |
949 SetActive(false); | |
950 } | |
951 | |
952 | |
953 } } // namespace v8::internal | 759 } } // namespace v8::internal |
OLD | NEW |