From 9585ead1e9002cf993494ba59ce5d593fe0016da Mon Sep 17 00:00:00 2001 From: "yurys@chromium.org" Date: Tue, 16 Apr 2013 08:54:33 +0000 Subject: [PATCH] This change is a continuation of the refactoring started in r14265. Renamed SignalSender to SamplerThread to match platforms that don't support signal sending. Cygwin and Windows implementations are almost identical. Mac OS X uses different API to suspend thread but apart from that it is very similar to Windows implenenation. BUG=None Review URL: https://codereview.chromium.org/14264009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14272 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/isolate.cc | 15 ++- src/platform-cygwin.cc | 194 -------------------------------- src/platform-macos.cc | 194 -------------------------------- src/platform-win32.cc | 192 -------------------------------- src/sampler.cc | 297 ++++++++++++++++++++++++++++++++++++++++++------- 5 files changed, 265 insertions(+), 627 deletions(-) diff --git a/src/isolate.cc b/src/isolate.cc index cd6ee47..fc5a225 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -1841,11 +1841,6 @@ void Isolate::Deinit() { preallocated_message_space_ = NULL; PreallocatedMemoryThreadStop(); - delete heap_profiler_; - heap_profiler_ = NULL; - delete cpu_profiler_; - cpu_profiler_ = NULL; - if (runtime_profiler_ != NULL) { runtime_profiler_->TearDown(); delete runtime_profiler_; @@ -1854,6 +1849,11 @@ void Isolate::Deinit() { heap_.TearDown(); logger_->TearDown(); + delete heap_profiler_; + heap_profiler_ = NULL; + delete cpu_profiler_; + cpu_profiler_ = NULL; + // The default isolate is re-initializable due to legacy API. state_ = UNINITIALIZED; } @@ -2070,13 +2070,12 @@ bool Isolate::Init(Deserializer* des) { date_cache_ = new DateCache(); code_stub_interface_descriptors_ = new CodeStubInterfaceDescriptor[CodeStub::NUMBER_OF_IDS]; + cpu_profiler_ = new CpuProfiler(this); + heap_profiler_ = new HeapProfiler(heap()); // Enable logging before setting up the heap logger_->SetUp(); - cpu_profiler_ = new CpuProfiler(this); - heap_profiler_ = new HeapProfiler(heap()); - // Initialize other runtime facilities #if defined(USE_SIMULATOR) #if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS) diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc index 418a05e..e13a3a6 100644 --- a/src/platform-cygwin.cc +++ b/src/platform-cygwin.cc @@ -623,168 +623,6 @@ Semaphore* OS::CreateSemaphore(int count) { } -// ---------------------------------------------------------------------------- -// Cygwin profiler support. -// -// On Cygwin we use the same sampler implementation as on win32. - -class Sampler::PlatformData : public Malloced { - public: - // Get a handle to the calling thread. This is the thread that we are - // going to profile. We need to make a copy of the handle because we are - // going to use it in the sampler thread. Using GetThreadHandle() will - // not work in this case. We're using OpenThread because DuplicateHandle - // for some reason doesn't work in Chrome's sandbox. - PlatformData() - : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | - THREAD_SUSPEND_RESUME | - THREAD_QUERY_INFORMATION, - false, - GetCurrentThreadId())), - profiled_thread_id_(ThreadId::Current()) {} - - ~PlatformData() { - if (profiled_thread_ != NULL) { - CloseHandle(profiled_thread_); - profiled_thread_ = NULL; - } - } - - HANDLE profiled_thread() { return profiled_thread_; } - ThreadId profiled_thread_id() { return profiled_thread_id_; } - - private: - HANDLE profiled_thread_; - ThreadId profiled_thread_id_; -}; - - -class SamplerThread : public Thread { - public: - static const int kSamplerThreadStackSize = 64 * KB; - - explicit SamplerThread(int interval) - : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)), - interval_(interval) {} - - static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } - static void TearDown() { delete mutex_; } - - static void AddActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_); - SamplerRegistry::AddActiveSampler(sampler); - if (instance_ == NULL) { - instance_ = new SamplerThread(sampler->interval()); - instance_->StartSynchronously(); - } else { - ASSERT(instance_->interval_ == sampler->interval()); - } - } - - static void RemoveActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_); - SamplerRegistry::RemoveActiveSampler(sampler); - if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { - instance_->Join(); - delete instance_; - instance_ = NULL; - } - } - - // Implement Thread::Run(). - virtual void Run() { - SamplerRegistry::State state; - while ((state = SamplerRegistry::GetState()) != - SamplerRegistry::HAS_NO_SAMPLERS) { - // When CPU profiling is enabled both JavaScript and C++ code is - // profiled. We must not suspend. - if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { - SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); - } - OS::Sleep(interval_); - } - } - - static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) { - if (!sampler->isolate()->IsInitialized()) return; - if (!sampler->IsProfiling()) return; - SamplerThread* sampler_thread = - reinterpret_cast(raw_sampler_thread); - sampler_thread->SampleContext(sampler); - } - - void SampleContext(Sampler* sampler) { - HANDLE profiled_thread = sampler->platform_data()->profiled_thread(); - if (profiled_thread == NULL) return; - - // Context used for sampling the register state of the profiled thread. - CONTEXT context; - memset(&context, 0, sizeof(context)); - - Isolate* isolate = sampler->isolate(); -#if defined(USE_SIMULATOR) -#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS - ThreadId thread_id = sampler->platform_data()->profiled_thread_id(); - Isolate::PerIsolateThreadData* per_thread_data = isolate-> - FindPerThreadDataForThread(thread_id); - if (!per_thread_data) return; - Simulator* sim = per_thread_data->simulator(); - // Check if there is active simulator before allocating TickSample. - if (!sim) return; -#endif -#endif // USE_SIMULATOR - TickSample sample_obj; - TickSample* sample = isolate->cpu_profiler()->TickSampleEvent(); - if (sample == NULL) sample = &sample_obj; - - static const DWORD kSuspendFailed = static_cast(-1); - if (SuspendThread(profiled_thread) == kSuspendFailed) return; - sample->state = isolate->current_vm_state(); - - context.ContextFlags = CONTEXT_FULL; - if (GetThreadContext(profiled_thread, &context) != 0) { -#if defined(USE_SIMULATOR) -#if V8_TARGET_ARCH_ARM - sample->pc = reinterpret_cast
(sim->get_register(Simulator::pc)); - sample->sp = reinterpret_cast
(sim->get_register(Simulator::sp)); - sample->fp = reinterpret_cast
(sim->get_register(Simulator::r11)); -#elif V8_TARGET_ARCH_MIPS - sample->pc = reinterpret_cast
(sim->get_register(Simulator::pc)); - sample->sp = reinterpret_cast
(sim->get_register(Simulator::sp)); - sample->fp = reinterpret_cast
(sim->get_register(Simulator::fp)); -#endif -#else -#if V8_HOST_ARCH_X64 - sample->pc = reinterpret_cast
(context.Rip); - sample->sp = reinterpret_cast
(context.Rsp); - sample->fp = reinterpret_cast
(context.Rbp); -#else - sample->pc = reinterpret_cast
(context.Eip); - sample->sp = reinterpret_cast
(context.Esp); - sample->fp = reinterpret_cast
(context.Ebp); -#endif -#endif // USE_SIMULATOR - sampler->SampleStack(sample); - sampler->Tick(sample); - } - ResumeThread(profiled_thread); - } - - const int interval_; - - // Protects the process wide state below. - static Mutex* mutex_; - static SamplerThread* instance_; - - private: - DISALLOW_COPY_AND_ASSIGN(SamplerThread); -}; - - -Mutex* SamplerThread::mutex_ = NULL; -SamplerThread* SamplerThread::instance_ = NULL; - - void OS::SetUp() { // Seed the random number generator. // Convert the current time to a 64-bit integer first, before converting it @@ -794,44 +632,12 @@ void OS::SetUp() { uint64_t seed = static_cast(TimeCurrentMillis()); srandom(static_cast(seed)); limit_mutex = CreateMutex(); - SamplerThread::SetUp(); } void OS::TearDown() { - SamplerThread::TearDown(); delete limit_mutex; } -Sampler::Sampler(Isolate* isolate, int interval) - : isolate_(isolate), - interval_(interval), - profiling_(false), - active_(false), - samples_taken_(0) { - data_ = new PlatformData; -} - - -Sampler::~Sampler() { - ASSERT(!IsActive()); - delete data_; -} - - -void Sampler::Start() { - ASSERT(!IsActive()); - SetActive(true); - SamplerThread::AddActiveSampler(this); -} - - -void Sampler::Stop() { - ASSERT(IsActive()); - SamplerThread::RemoveActiveSampler(this); - SetActive(false); -} - - } } // namespace v8::internal diff --git a/src/platform-macos.cc b/src/platform-macos.cc index 8327acf..9bb4dbd 100644 --- a/src/platform-macos.cc +++ b/src/platform-macos.cc @@ -743,211 +743,17 @@ Semaphore* OS::CreateSemaphore(int count) { } -class Sampler::PlatformData : public Malloced { - public: - PlatformData() - : profiled_thread_(mach_thread_self()), - profiled_thread_id_(ThreadId::Current()) {} - - ~PlatformData() { - // Deallocate Mach port for thread. - mach_port_deallocate(mach_task_self(), profiled_thread_); - } - - thread_act_t profiled_thread() { return profiled_thread_; } - ThreadId profiled_thread_id() { return profiled_thread_id_; } - - private: - // Note: for profiled_thread_ Mach primitives are used instead of PThread's - // because the latter doesn't provide thread manipulation primitives required. - // For details, consult "Mac OS X Internals" book, Section 7.3. - thread_act_t profiled_thread_; - ThreadId profiled_thread_id_; -}; - - -class SamplerThread : public Thread { - public: - static const int kSamplerThreadStackSize = 64 * KB; - - explicit SamplerThread(int interval) - : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)), - interval_(interval) {} - - static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } - static void TearDown() { delete mutex_; } - - static void AddActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_); - SamplerRegistry::AddActiveSampler(sampler); - if (instance_ == NULL) { - instance_ = new SamplerThread(sampler->interval()); - instance_->StartSynchronously(); - } else { - ASSERT(instance_->interval_ == sampler->interval()); - } - } - - static void RemoveActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_); - SamplerRegistry::RemoveActiveSampler(sampler); - if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { - instance_->Join(); - delete instance_; - instance_ = NULL; - } - } - - // Implement Thread::Run(). - virtual void Run() { - SamplerRegistry::State state; - while ((state = SamplerRegistry::GetState()) != - SamplerRegistry::HAS_NO_SAMPLERS) { - // When CPU profiling is enabled both JavaScript and C++ code is - // profiled. We must not suspend. - if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { - SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); - } - OS::Sleep(interval_); - } - } - - static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) { - if (!sampler->isolate()->IsInitialized()) return; - if (!sampler->IsProfiling()) return; - SamplerThread* sampler_thread = - reinterpret_cast(raw_sampler_thread); - sampler_thread->SampleContext(sampler); - } - - void SampleContext(Sampler* sampler) { - thread_act_t profiled_thread = sampler->platform_data()->profiled_thread(); - Isolate* isolate = sampler->isolate(); -#if defined(USE_SIMULATOR) -#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS - ThreadId thread_id = sampler->platform_data()->profiled_thread_id(); - Isolate::PerIsolateThreadData* per_thread_data = isolate-> - FindPerThreadDataForThread(thread_id); - if (!per_thread_data) return; - Simulator* sim = per_thread_data->simulator(); - // Check if there is active simulator before allocating TickSample. - if (!sim) return; -#endif -#endif // USE_SIMULATOR - TickSample sample_obj; - TickSample* sample = isolate->cpu_profiler()->TickSampleEvent(); - if (sample == NULL) sample = &sample_obj; - - if (KERN_SUCCESS != thread_suspend(profiled_thread)) return; - -#if V8_HOST_ARCH_X64 - thread_state_flavor_t flavor = x86_THREAD_STATE64; - x86_thread_state64_t state; - mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; -#if __DARWIN_UNIX03 -#define REGISTER_FIELD(name) __r ## name -#else -#define REGISTER_FIELD(name) r ## name -#endif // __DARWIN_UNIX03 -#elif V8_HOST_ARCH_IA32 - thread_state_flavor_t flavor = i386_THREAD_STATE; - i386_thread_state_t state; - mach_msg_type_number_t count = i386_THREAD_STATE_COUNT; -#if __DARWIN_UNIX03 -#define REGISTER_FIELD(name) __e ## name -#else -#define REGISTER_FIELD(name) e ## name -#endif // __DARWIN_UNIX03 -#else -#error Unsupported Mac OS X host architecture. -#endif // V8_HOST_ARCH - - if (thread_get_state(profiled_thread, - flavor, - reinterpret_cast(&state), - &count) == KERN_SUCCESS) { - sample->state = isolate->current_vm_state(); -#if defined(USE_SIMULATOR) -#if V8_TARGET_ARCH_ARM - sample->pc = reinterpret_cast
(sim->get_register(Simulator::pc)); - sample->sp = reinterpret_cast
(sim->get_register(Simulator::sp)); - sample->fp = reinterpret_cast
(sim->get_register(Simulator::r11)); -#elif V8_TARGET_ARCH_MIPS - sample->pc = reinterpret_cast
(sim->get_register(Simulator::pc)); - sample->sp = reinterpret_cast
(sim->get_register(Simulator::sp)); - sample->fp = reinterpret_cast
(sim->get_register(Simulator::fp)); -#endif -#else - sample->pc = reinterpret_cast
(state.REGISTER_FIELD(ip)); - sample->sp = reinterpret_cast
(state.REGISTER_FIELD(sp)); - sample->fp = reinterpret_cast
(state.REGISTER_FIELD(bp)); -#endif // USE_SIMULATOR - sampler->SampleStack(sample); - sampler->Tick(sample); - } - thread_resume(profiled_thread); - } - - const int interval_; - - // Protects the process wide state below. - static Mutex* mutex_; - static SamplerThread* instance_; - - private: - DISALLOW_COPY_AND_ASSIGN(SamplerThread); -}; - -#undef REGISTER_FIELD - - -Mutex* SamplerThread::mutex_ = NULL; -SamplerThread* SamplerThread::instance_ = NULL; - - void OS::SetUp() { // Seed the random number generator. We preserve microsecond resolution. uint64_t seed = Ticks() ^ (getpid() << 16); srandom(static_cast(seed)); limit_mutex = CreateMutex(); - SamplerThread::SetUp(); } void OS::TearDown() { - SamplerThread::TearDown(); delete limit_mutex; } -Sampler::Sampler(Isolate* isolate, int interval) - : isolate_(isolate), - interval_(interval), - profiling_(false), - active_(false), - samples_taken_(0) { - data_ = new PlatformData; -} - - -Sampler::~Sampler() { - ASSERT(!IsActive()); - delete data_; -} - - -void Sampler::Start() { - ASSERT(!IsActive()); - SetActive(true); - SamplerThread::AddActiveSampler(this); -} - - -void Sampler::Stop() { - ASSERT(IsActive()); - SamplerThread::RemoveActiveSampler(this); - SetActive(false); -} - - } } // namespace v8::internal diff --git a/src/platform-win32.cc b/src/platform-win32.cc index f9c2ce7..78d1ac5 100644 --- a/src/platform-win32.cc +++ b/src/platform-win32.cc @@ -1968,166 +1968,6 @@ Socket* OS::CreateSocket() { } -// ---------------------------------------------------------------------------- -// Win32 profiler support. - -class Sampler::PlatformData : public Malloced { - public: - // Get a handle to the calling thread. This is the thread that we are - // going to profile. We need to make a copy of the handle because we are - // going to use it in the sampler thread. Using GetThreadHandle() will - // not work in this case. We're using OpenThread because DuplicateHandle - // for some reason doesn't work in Chrome's sandbox. - PlatformData() - : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | - THREAD_SUSPEND_RESUME | - THREAD_QUERY_INFORMATION, - false, - GetCurrentThreadId())), - profiled_thread_id_(ThreadId::Current()) {} - - ~PlatformData() { - if (profiled_thread_ != NULL) { - CloseHandle(profiled_thread_); - profiled_thread_ = NULL; - } - } - - HANDLE profiled_thread() { return profiled_thread_; } - ThreadId profiled_thread_id() { return profiled_thread_id_; } - - private: - HANDLE profiled_thread_; - ThreadId profiled_thread_id_; -}; - - -class SamplerThread : public Thread { - public: - static const int kSamplerThreadStackSize = 64 * KB; - - explicit SamplerThread(int interval) - : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)), - interval_(interval) {} - - static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } - static void TearDown() { delete mutex_; } - - static void AddActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_); - SamplerRegistry::AddActiveSampler(sampler); - if (instance_ == NULL) { - instance_ = new SamplerThread(sampler->interval()); - instance_->StartSynchronously(); - } else { - ASSERT(instance_->interval_ == sampler->interval()); - } - } - - static void RemoveActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_); - SamplerRegistry::RemoveActiveSampler(sampler); - if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { - instance_->Join(); - delete instance_; - instance_ = NULL; - } - } - - // Implement Thread::Run(). - virtual void Run() { - SamplerRegistry::State state; - while ((state = SamplerRegistry::GetState()) != - SamplerRegistry::HAS_NO_SAMPLERS) { - // When CPU profiling is enabled both JavaScript and C++ code is - // profiled. We must not suspend. - if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { - SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); - } - OS::Sleep(interval_); - } - } - - static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) { - if (!sampler->isolate()->IsInitialized()) return; - if (!sampler->IsProfiling()) return; - SamplerThread* sampler_thread = - reinterpret_cast(raw_sampler_thread); - sampler_thread->SampleContext(sampler); - } - - void SampleContext(Sampler* sampler) { - HANDLE profiled_thread = sampler->platform_data()->profiled_thread(); - if (profiled_thread == NULL) return; - - // Context used for sampling the register state of the profiled thread. - CONTEXT context; - memset(&context, 0, sizeof(context)); - - Isolate* isolate = sampler->isolate(); -#if defined(USE_SIMULATOR) -#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS - ThreadId thread_id = sampler->platform_data()->profiled_thread_id(); - Isolate::PerIsolateThreadData* per_thread_data = isolate-> - FindPerThreadDataForThread(thread_id); - if (!per_thread_data) return; - Simulator* sim = per_thread_data->simulator(); - // Check if there is active simulator before allocating TickSample. - if (!sim) return; -#endif -#endif // USE_SIMULATOR - TickSample sample_obj; - TickSample* sample = isolate->cpu_profiler()->TickSampleEvent(); - if (sample == NULL) sample = &sample_obj; - - static const DWORD kSuspendFailed = static_cast(-1); - if (SuspendThread(profiled_thread) == kSuspendFailed) return; - sample->state = isolate->current_vm_state(); - - context.ContextFlags = CONTEXT_FULL; - if (GetThreadContext(profiled_thread, &context) != 0) { -#if defined(USE_SIMULATOR) -#if V8_TARGET_ARCH_ARM - sample->pc = reinterpret_cast
(sim->get_register(Simulator::pc)); - sample->sp = reinterpret_cast
(sim->get_register(Simulator::sp)); - sample->fp = reinterpret_cast
(sim->get_register(Simulator::r11)); -#elif V8_TARGET_ARCH_MIPS - sample->pc = reinterpret_cast
(sim->get_register(Simulator::pc)); - sample->sp = reinterpret_cast
(sim->get_register(Simulator::sp)); - sample->fp = reinterpret_cast
(sim->get_register(Simulator::fp)); -#endif -#else -#if V8_HOST_ARCH_X64 - sample->pc = reinterpret_cast
(context.Rip); - sample->sp = reinterpret_cast
(context.Rsp); - sample->fp = reinterpret_cast
(context.Rbp); -#else - sample->pc = reinterpret_cast
(context.Eip); - sample->sp = reinterpret_cast
(context.Esp); - sample->fp = reinterpret_cast
(context.Ebp); -#endif -#endif // USE_SIMULATOR - sampler->SampleStack(sample); - sampler->Tick(sample); - } - ResumeThread(profiled_thread); - } - - const int interval_; - - // Protects the process wide state below. - static Mutex* mutex_; - static SamplerThread* instance_; - - private: - DISALLOW_COPY_AND_ASSIGN(SamplerThread); -}; - - -Mutex* SamplerThread::mutex_ = NULL; -SamplerThread* SamplerThread::instance_ = NULL; - - void OS::SetUp() { // Seed the random number generator. // Convert the current time to a 64-bit integer first, before converting it @@ -2137,44 +1977,12 @@ void OS::SetUp() { uint64_t seed = static_cast(TimeCurrentMillis()); srand(static_cast(seed)); limit_mutex = CreateMutex(); - SamplerThread::SetUp(); } void OS::TearDown() { - SamplerThread::TearDown(); delete limit_mutex; } -Sampler::Sampler(Isolate* isolate, int interval) - : isolate_(isolate), - interval_(interval), - profiling_(false), - active_(false), - samples_taken_(0) { - data_ = new PlatformData; -} - - -Sampler::~Sampler() { - ASSERT(!IsActive()); - delete data_; -} - - -void Sampler::Start() { - ASSERT(!IsActive()); - SetActive(true); - SamplerThread::AddActiveSampler(this); -} - - -void Sampler::Stop() { - ASSERT(IsActive()); - SamplerThread::RemoveActiveSampler(this); - SetActive(false); -} - - } } // namespace v8::internal diff --git a/src/sampler.cc b/src/sampler.cc index 446f996..55b943c 100644 --- a/src/sampler.cc +++ b/src/sampler.cc @@ -26,17 +26,19 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ - || defined(__NetBSD__) || defined(__sun) + || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__) + +#define USE_SIGNALS #include #include #include #include #include +#if !defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T) #include -#include - #endif +#include // GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'. // Old versions of the C library didn't define the type. @@ -45,6 +47,16 @@ #include #endif +#elif defined(__MACH__) + +#include + +#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + +#include "win32-headers.h" + +#endif + #include "v8.h" #include "log.h" @@ -58,7 +70,7 @@ namespace internal { #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ - || defined(__NetBSD__) || defined(__sun) + || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__) #if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) @@ -153,13 +165,16 @@ class Sampler::PlatformData : public Malloced { public: PlatformData() : vm_tid_(GetThreadID()), + vm_tgid_(getpid()), profiled_thread_id_(ThreadId::Current()) {} pthread_t vm_tid() const { return vm_tid_; } + int vm_tgid() const { return vm_tgid_; } ThreadId profiled_thread_id() { return profiled_thread_id_; } private: pthread_t vm_tid_; + const int vm_tgid_; ThreadId profiled_thread_id_; }; @@ -216,7 +231,7 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { ucontext_t* ucontext = reinterpret_cast(context); mcontext_t& mcontext = ucontext->uc_mcontext; sample->state = isolate->current_vm_state(); -#if defined(__linux__) +#if defined(__linux__) || defined(__ANDROID__) #if V8_HOST_ARCH_IA32 sample->pc = reinterpret_cast
(mcontext.gregs[REG_EIP]); sample->sp = reinterpret_cast
(mcontext.gregs[REG_ESP]); @@ -291,19 +306,80 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { #endif // __native_client__ } +#elif defined(__MACH__) +class Sampler::PlatformData : public Malloced { + public: + PlatformData() + : profiled_thread_(mach_thread_self()), + profiled_thread_id_(ThreadId::Current()) {} + + ~PlatformData() { + // Deallocate Mach port for thread. + mach_port_deallocate(mach_task_self(), profiled_thread_); + } -class SignalSender : public Thread { + thread_act_t profiled_thread() { return profiled_thread_; } + ThreadId profiled_thread_id() { return profiled_thread_id_; } + + private: + // Note: for profiled_thread_ Mach primitives are used instead of PThread's + // because the latter doesn't provide thread manipulation primitives required. + // For details, consult "Mac OS X Internals" book, Section 7.3. + thread_act_t profiled_thread_; + ThreadId profiled_thread_id_; +}; + +#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + +// ---------------------------------------------------------------------------- +// Win32 profiler support. On Cygwin we use the same sampler implementation as +// on Win32. + +class Sampler::PlatformData : public Malloced { public: - static const int kSignalSenderStackSize = 64 * KB; + // Get a handle to the calling thread. This is the thread that we are + // going to profile. We need to make a copy of the handle because we are + // going to use it in the sampler thread. Using GetThreadHandle() will + // not work in this case. We're using OpenThread because DuplicateHandle + // for some reason doesn't work in Chrome's sandbox. + PlatformData() + : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | + THREAD_SUSPEND_RESUME | + THREAD_QUERY_INFORMATION, + false, + GetCurrentThreadId())), + profiled_thread_id_(ThreadId::Current()) {} - explicit SignalSender(int interval) - : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)), - vm_tgid_(getpid()), + ~PlatformData() { + if (profiled_thread_ != NULL) { + CloseHandle(profiled_thread_); + profiled_thread_ = NULL; + } + } + + HANDLE profiled_thread() { return profiled_thread_; } + ThreadId profiled_thread_id() { return profiled_thread_id_; } + + private: + HANDLE profiled_thread_; + ThreadId profiled_thread_id_; +}; + +#endif + + +class SamplerThread : public Thread { + public: + static const int kSamplerThreadStackSize = 64 * KB; + + explicit SamplerThread(int interval) + : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)), interval_(interval) {} static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } static void TearDown() { delete mutex_; } +#if defined(USE_SIGNALS) static void InstallSignalHandler() { struct sigaction sa; sa.sa_sigaction = ProfilerSignalHandler; @@ -319,6 +395,7 @@ class SignalSender : public Thread { signal_handler_installed_ = false; } } +#endif static void AddActiveSampler(Sampler* sampler) { ScopedLock lock(mutex_); @@ -326,7 +403,7 @@ class SignalSender : public Thread { if (instance_ == NULL) { // Start a thread that will send SIGPROF signal to VM threads, // when CPU profiling will be enabled. - instance_ = new SignalSender(sampler->interval()); + instance_ = new SamplerThread(sampler->interval()); instance_->StartSynchronously(); } else { ASSERT(instance_->interval_ == sampler->interval()); @@ -340,7 +417,9 @@ class SignalSender : public Thread { instance_->Join(); delete instance_; instance_ = NULL; +#if defined(USE_SIGNALS) RestoreSignalHandler(); +#endif } } @@ -352,31 +431,39 @@ class SignalSender : public Thread { // When CPU profiling is enabled both JavaScript and C++ code is // profiled. We must not suspend. if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { +#if defined(USE_SIGNALS) if (!signal_handler_installed_) InstallSignalHandler(); +#endif SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); } else { +#if defined(USE_SIGNALS) if (signal_handler_installed_) RestoreSignalHandler(); +#endif } Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough. } } static void DoCpuProfile(Sampler* sampler, void* raw_sender) { + if (!sampler->isolate()->IsInitialized()) return; if (!sampler->IsProfiling()) return; - SignalSender* sender = reinterpret_cast(raw_sender); - sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); + SamplerThread* sender = reinterpret_cast(raw_sender); + sender->SampleContext(sampler); } - void SendProfilingSignal(int tid) { +#if defined(USE_SIGNALS) + void SampleContext(Sampler* sampler) { if (!signal_handler_installed_) return; + Sampler::PlatformData* platform_data = sampler->platform_data(); + int tid = platform_data->vm_tid(); // Glibc doesn't provide a wrapper for tgkill(2). #if defined(ANDROID) - syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF); + syscall(__NR_tgkill, platform_data->vm_tgid(), tid, SIGPROF); #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ || defined(__sun) pthread_kill(tid, SIGPROF); #else - int result = syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF); + int result = syscall(SYS_tgkill, platform_data->vm_tgid(), tid, SIGPROF); USE(result); ASSERT(result == 0); #endif @@ -393,7 +480,7 @@ class SignalSender : public Thread { #ifdef DEBUG if (result != 0 && errno != EINTR) { fprintf(stderr, - "SignalSender usleep error; interval = %u, errno = %d\n", + "SamplerThread usleep error; interval = %u, errno = %d\n", interval, errno); ASSERT(result == 0 || errno == EINTR); @@ -403,33 +490,176 @@ class SignalSender : public Thread { #endif // ANDROID } - const int vm_tgid_; +#elif defined(__MACH__) + + void SampleContext(Sampler* sampler) { + thread_act_t profiled_thread = sampler->platform_data()->profiled_thread(); + Isolate* isolate = sampler->isolate(); +#if defined(USE_SIMULATOR) +#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS + ThreadId thread_id = sampler->platform_data()->profiled_thread_id(); + Isolate::PerIsolateThreadData* per_thread_data = isolate-> + FindPerThreadDataForThread(thread_id); + if (!per_thread_data) return; + Simulator* sim = per_thread_data->simulator(); + // Check if there is active simulator before allocating TickSample. + if (!sim) return; +#endif +#endif // USE_SIMULATOR + TickSample sample_obj; + TickSample* sample = isolate->cpu_profiler()->TickSampleEvent(); + if (sample == NULL) sample = &sample_obj; + + if (KERN_SUCCESS != thread_suspend(profiled_thread)) return; + +#if V8_HOST_ARCH_X64 + thread_state_flavor_t flavor = x86_THREAD_STATE64; + x86_thread_state64_t state; + mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; +#if __DARWIN_UNIX03 +#define REGISTER_FIELD(name) __r ## name +#else +#define REGISTER_FIELD(name) r ## name +#endif // __DARWIN_UNIX03 +#elif V8_HOST_ARCH_IA32 + thread_state_flavor_t flavor = i386_THREAD_STATE; + i386_thread_state_t state; + mach_msg_type_number_t count = i386_THREAD_STATE_COUNT; +#if __DARWIN_UNIX03 +#define REGISTER_FIELD(name) __e ## name +#else +#define REGISTER_FIELD(name) e ## name +#endif // __DARWIN_UNIX03 +#else +#error Unsupported Mac OS X host architecture. +#endif // V8_HOST_ARCH + + if (thread_get_state(profiled_thread, + flavor, + reinterpret_cast(&state), + &count) == KERN_SUCCESS) { + sample->state = isolate->current_vm_state(); +#if defined(USE_SIMULATOR) +#if V8_TARGET_ARCH_ARM + sample->pc = reinterpret_cast
(sim->get_register(Simulator::pc)); + sample->sp = reinterpret_cast
(sim->get_register(Simulator::sp)); + sample->fp = reinterpret_cast
(sim->get_register(Simulator::r11)); +#elif V8_TARGET_ARCH_MIPS + sample->pc = reinterpret_cast
(sim->get_register(Simulator::pc)); + sample->sp = reinterpret_cast
(sim->get_register(Simulator::sp)); + sample->fp = reinterpret_cast
(sim->get_register(Simulator::fp)); +#endif +#else + sample->pc = reinterpret_cast
(state.REGISTER_FIELD(ip)); + sample->sp = reinterpret_cast
(state.REGISTER_FIELD(sp)); + sample->fp = reinterpret_cast
(state.REGISTER_FIELD(bp)); +#endif // USE_SIMULATOR +#undef REGISTER_FIELD + sampler->SampleStack(sample); + sampler->Tick(sample); + } + thread_resume(profiled_thread); + } + + void Sleep() { + OS::Sleep(interval_); + } + +#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + + void SampleContext(Sampler* sampler) { + HANDLE profiled_thread = sampler->platform_data()->profiled_thread(); + if (profiled_thread == NULL) return; + + // Context used for sampling the register state of the profiled thread. + CONTEXT context; + memset(&context, 0, sizeof(context)); + + Isolate* isolate = sampler->isolate(); +#if defined(USE_SIMULATOR) +#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS + ThreadId thread_id = sampler->platform_data()->profiled_thread_id(); + Isolate::PerIsolateThreadData* per_thread_data = isolate-> + FindPerThreadDataForThread(thread_id); + if (!per_thread_data) return; + Simulator* sim = per_thread_data->simulator(); + // Check if there is active simulator before allocating TickSample. + if (!sim) return; +#endif +#endif // USE_SIMULATOR + TickSample sample_obj; + TickSample* sample = isolate->cpu_profiler()->TickSampleEvent(); + if (sample == NULL) sample = &sample_obj; + + static const DWORD kSuspendFailed = static_cast(-1); + if (SuspendThread(profiled_thread) == kSuspendFailed) return; + sample->state = isolate->current_vm_state(); + + context.ContextFlags = CONTEXT_FULL; + if (GetThreadContext(profiled_thread, &context) != 0) { +#if defined(USE_SIMULATOR) +#if V8_TARGET_ARCH_ARM + sample->pc = reinterpret_cast
(sim->get_register(Simulator::pc)); + sample->sp = reinterpret_cast
(sim->get_register(Simulator::sp)); + sample->fp = reinterpret_cast
(sim->get_register(Simulator::r11)); +#elif V8_TARGET_ARCH_MIPS + sample->pc = reinterpret_cast
(sim->get_register(Simulator::pc)); + sample->sp = reinterpret_cast
(sim->get_register(Simulator::sp)); + sample->fp = reinterpret_cast
(sim->get_register(Simulator::fp)); +#endif +#else +#if V8_HOST_ARCH_X64 + sample->pc = reinterpret_cast
(context.Rip); + sample->sp = reinterpret_cast
(context.Rsp); + sample->fp = reinterpret_cast
(context.Rbp); +#else + sample->pc = reinterpret_cast
(context.Eip); + sample->sp = reinterpret_cast
(context.Esp); + sample->fp = reinterpret_cast
(context.Ebp); +#endif +#endif // USE_SIMULATOR + sampler->SampleStack(sample); + sampler->Tick(sample); + } + ResumeThread(profiled_thread); + } + + void Sleep() { + OS::Sleep(interval_); + } + +#endif // USE_SIGNALS + const int interval_; // Protects the process wide state below. static Mutex* mutex_; - static SignalSender* instance_; + static SamplerThread* instance_; +#if defined(USE_SIGNALS) static bool signal_handler_installed_; static struct sigaction old_signal_handler_; +#endif private: - DISALLOW_COPY_AND_ASSIGN(SignalSender); + DISALLOW_COPY_AND_ASSIGN(SamplerThread); }; -Mutex* SignalSender::mutex_ = NULL; -SignalSender* SignalSender::instance_ = NULL; -struct sigaction SignalSender::old_signal_handler_; -bool SignalSender::signal_handler_installed_ = false; +Mutex* SamplerThread::mutex_ = NULL; +SamplerThread* SamplerThread::instance_ = NULL; +#if defined(USE_SIGNALS) +struct sigaction SamplerThread::old_signal_handler_; +bool SamplerThread::signal_handler_installed_ = false; +#endif void Sampler::SetUp() { - SignalSender::SetUp(); + SamplerThread::SetUp(); } void Sampler::TearDown() { - SignalSender::TearDown(); + SamplerThread::TearDown(); } @@ -451,27 +681,16 @@ Sampler::~Sampler() { void Sampler::Start() { ASSERT(!IsActive()); SetActive(true); - SignalSender::AddActiveSampler(this); + SamplerThread::AddActiveSampler(this); } void Sampler::Stop() { ASSERT(IsActive()); - SignalSender::RemoveActiveSampler(this); + SamplerThread::RemoveActiveSampler(this); SetActive(false); } -#else - -void Sampler::SetUp() { -} - - -void Sampler::TearDown() { -} - -#endif // __linux__ || _*BSD__ || __sun - void Sampler::SampleStack(TickSample* sample) { StackTracer::Trace(isolate_, sample); if (++samples_taken_ < 0) samples_taken_ = 0; -- 2.7.4