| 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 |