Use signals for cpu profiling on Mac OS X
A while ago in r2315 Mac OS X cpu profiler implementation was changed to pause sampled thread instead of sending SIGPROF signal. That was done because at that point profiler send the signal to the whole process and it was handled on a random thread. Now that signal-based implementation uses pthread_kill it may well be used on Mac OS X too. BUG=v8:2814 R=bmeurer@chromium.org, svenpanne@chromium.org Review URL: https://codereview.chromium.org/23115005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16320 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
c8bdc10646
commit
a29ceb7b27
@ -436,7 +436,6 @@ void CpuProfiler::StartProcessorIfNotStarted() {
|
||||
processor_ = new ProfilerEventsProcessor(
|
||||
generator_, sampler, FLAG_cpu_profiler_sampling_interval);
|
||||
is_profiling_ = true;
|
||||
processor_->StartSynchronously();
|
||||
// Enumerate stuff we already have in the heap.
|
||||
ASSERT(isolate_->heap()->HasBeenSetUp());
|
||||
if (!FLAG_prof_browser_mode) {
|
||||
@ -454,6 +453,7 @@ void CpuProfiler::StartProcessorIfNotStarted() {
|
||||
sampler->Start();
|
||||
need_to_stop_sampler_ = true;
|
||||
}
|
||||
processor_->StartSynchronously();
|
||||
}
|
||||
}
|
||||
|
||||
|
215
src/sampler.cc
215
src/sampler.cc
@ -29,7 +29,7 @@
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
|
||||
|| defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__) \
|
||||
|| defined(__native_client__)
|
||||
|| defined(__native_client__) || defined(__MACH__)
|
||||
|
||||
#define USE_SIGNALS
|
||||
|
||||
@ -38,9 +38,12 @@
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#if defined(__MACH__)
|
||||
#include <mach/mach.h>
|
||||
// OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h>
|
||||
// and is a typedef for struct sigcontext. There is no uc_mcontext.
|
||||
#if (!defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)) \
|
||||
#elif(!defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)) \
|
||||
&& !defined(__OpenBSD__)
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
@ -53,10 +56,6 @@
|
||||
#include <asm/sigcontext.h>
|
||||
#endif
|
||||
|
||||
#elif defined(__MACH__)
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
||||
|
||||
#include "win32-headers.h"
|
||||
@ -174,33 +173,12 @@ class PlatformDataCommon : public Malloced {
|
||||
class Sampler::PlatformData : public PlatformDataCommon {
|
||||
public:
|
||||
PlatformData() : vm_tid_(pthread_self()) {}
|
||||
|
||||
void SendProfilingSignal() const;
|
||||
pthread_t vm_tid() const { return vm_tid_; }
|
||||
|
||||
private:
|
||||
pthread_t vm_tid_;
|
||||
};
|
||||
|
||||
#elif defined(__MACH__)
|
||||
|
||||
class Sampler::PlatformData : public PlatformDataCommon {
|
||||
public:
|
||||
PlatformData() : profiled_thread_(mach_thread_self()) {}
|
||||
|
||||
~PlatformData() {
|
||||
// Deallocate Mach port for thread.
|
||||
mach_port_deallocate(mach_task_self(), profiled_thread_);
|
||||
}
|
||||
|
||||
thread_act_t profiled_thread() { return profiled_thread_; }
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -365,6 +343,28 @@ void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
|
||||
state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
|
||||
state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
|
||||
#endif // V8_HOST_ARCH_*
|
||||
#elif defined(__MACH__)
|
||||
#if V8_HOST_ARCH_X64
|
||||
#if __DARWIN_UNIX03
|
||||
state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip);
|
||||
state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp);
|
||||
state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp);
|
||||
#else // !__DARWIN_UNIX03
|
||||
state.pc = reinterpret_cast<Address>(mcontext->ss.rip);
|
||||
state.sp = reinterpret_cast<Address>(mcontext->ss.rsp);
|
||||
state.fp = reinterpret_cast<Address>(mcontext->ss.rbp);
|
||||
#endif // __DARWIN_UNIX03
|
||||
#elif V8_HOST_ARCH_IA32
|
||||
#if __DARWIN_UNIX03
|
||||
state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip);
|
||||
state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp);
|
||||
state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp);
|
||||
#else // !__DARWIN_UNIX03
|
||||
state.pc = reinterpret_cast<Address>(mcontext->ss.eip);
|
||||
state.sp = reinterpret_cast<Address>(mcontext->ss.esp);
|
||||
state.fp = reinterpret_cast<Address>(mcontext->ss.ebp);
|
||||
#endif // __DARWIN_UNIX03
|
||||
#endif // V8_HOST_ARCH_IA32
|
||||
#elif defined(__FreeBSD__)
|
||||
#if V8_HOST_ARCH_IA32
|
||||
state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
|
||||
@ -482,7 +482,7 @@ class SamplerThread : public Thread {
|
||||
Sampler* sampler = active_samplers_.at(i);
|
||||
if (!sampler->isolate()->IsInitialized()) continue;
|
||||
if (!sampler->IsProfiling()) continue;
|
||||
SampleContext(sampler);
|
||||
sampler->DoSample();
|
||||
}
|
||||
}
|
||||
OS::Sleep(interval_);
|
||||
@ -490,107 +490,6 @@ class SamplerThread : public Thread {
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(USE_SIGNALS)
|
||||
|
||||
void SampleContext(Sampler* sampler) {
|
||||
sampler->platform_data()->SendProfilingSignal();
|
||||
}
|
||||
|
||||
#elif defined(__MACH__)
|
||||
|
||||
void SampleContext(Sampler* sampler) {
|
||||
thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
|
||||
|
||||
#if defined(USE_SIMULATOR)
|
||||
SimulatorHelper helper;
|
||||
Isolate* isolate = sampler->isolate();
|
||||
if (!helper.Init(sampler, isolate)) return;
|
||||
#endif
|
||||
|
||||
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 thread_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 thread_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<natural_t*>(&thread_state),
|
||||
&count) == KERN_SUCCESS) {
|
||||
RegisterState state;
|
||||
#if defined(USE_SIMULATOR)
|
||||
helper.FillRegisters(&state);
|
||||
#else
|
||||
state.pc = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(ip));
|
||||
state.sp = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(sp));
|
||||
state.fp = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(bp));
|
||||
#endif // USE_SIMULATOR
|
||||
#undef REGISTER_FIELD
|
||||
sampler->SampleStack(state);
|
||||
}
|
||||
thread_resume(profiled_thread);
|
||||
}
|
||||
|
||||
#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
||||
|
||||
void SampleContext(Sampler* sampler) {
|
||||
HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
|
||||
if (profiled_thread == NULL) return;
|
||||
|
||||
Isolate* isolate = sampler->isolate();
|
||||
#if defined(USE_SIMULATOR)
|
||||
SimulatorHelper helper;
|
||||
if (!helper.Init(sampler, isolate)) return;
|
||||
#endif
|
||||
|
||||
const DWORD kSuspendFailed = static_cast<DWORD>(-1);
|
||||
if (SuspendThread(profiled_thread) == kSuspendFailed) return;
|
||||
|
||||
// Context used for sampling the register state of the profiled thread.
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
if (GetThreadContext(profiled_thread, &context) != 0) {
|
||||
RegisterState state;
|
||||
#if defined(USE_SIMULATOR)
|
||||
helper.FillRegisters(&state);
|
||||
#else
|
||||
#if V8_HOST_ARCH_X64
|
||||
state.pc = reinterpret_cast<Address>(context.Rip);
|
||||
state.sp = reinterpret_cast<Address>(context.Rsp);
|
||||
state.fp = reinterpret_cast<Address>(context.Rbp);
|
||||
#else
|
||||
state.pc = reinterpret_cast<Address>(context.Eip);
|
||||
state.sp = reinterpret_cast<Address>(context.Esp);
|
||||
state.fp = reinterpret_cast<Address>(context.Ebp);
|
||||
#endif
|
||||
#endif // USE_SIMULATOR
|
||||
sampler->SampleStack(state);
|
||||
}
|
||||
ResumeThread(profiled_thread);
|
||||
}
|
||||
|
||||
#endif // USE_SIGNALS
|
||||
|
||||
|
||||
// Protects the process wide state below.
|
||||
static Mutex* mutex_;
|
||||
static SamplerThread* instance_;
|
||||
@ -606,14 +505,6 @@ Mutex* SamplerThread::mutex_ = NULL;
|
||||
SamplerThread* SamplerThread::instance_ = NULL;
|
||||
|
||||
|
||||
#if defined(USE_SIGNALS)
|
||||
void Sampler::PlatformData::SendProfilingSignal() const {
|
||||
if (!SignalHandler::Installed()) return;
|
||||
pthread_kill(vm_tid_, SIGPROF);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// StackTracer implementation
|
||||
//
|
||||
@ -726,10 +617,52 @@ bool Sampler::CanSampleOnProfilerEventsProcessorThread() {
|
||||
}
|
||||
|
||||
|
||||
void Sampler::DoSample() {
|
||||
#if defined(USE_SIGNALS)
|
||||
platform_data()->SendProfilingSignal();
|
||||
#endif
|
||||
|
||||
void Sampler::DoSample() {
|
||||
if (!SignalHandler::Installed()) return;
|
||||
pthread_kill(platform_data()->vm_tid(), SIGPROF);
|
||||
}
|
||||
|
||||
#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
||||
|
||||
void Sampler::DoSample() {
|
||||
HANDLE profiled_thread = platform_data()->profiled_thread();
|
||||
if (profiled_thread == NULL) return;
|
||||
|
||||
#if defined(USE_SIMULATOR)
|
||||
SimulatorHelper helper;
|
||||
if (!helper.Init(this, isolate())) return;
|
||||
#endif
|
||||
|
||||
const DWORD kSuspendFailed = static_cast<DWORD>(-1);
|
||||
if (SuspendThread(profiled_thread) == kSuspendFailed) return;
|
||||
|
||||
// Context used for sampling the register state of the profiled thread.
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
if (GetThreadContext(profiled_thread, &context) != 0) {
|
||||
RegisterState state;
|
||||
#if defined(USE_SIMULATOR)
|
||||
helper.FillRegisters(&state);
|
||||
#else
|
||||
#if V8_HOST_ARCH_X64
|
||||
state.pc = reinterpret_cast<Address>(context.Rip);
|
||||
state.sp = reinterpret_cast<Address>(context.Rsp);
|
||||
state.fp = reinterpret_cast<Address>(context.Rbp);
|
||||
#else
|
||||
state.pc = reinterpret_cast<Address>(context.Eip);
|
||||
state.sp = reinterpret_cast<Address>(context.Esp);
|
||||
state.fp = reinterpret_cast<Address>(context.Ebp);
|
||||
#endif
|
||||
#endif // USE_SIMULATOR
|
||||
SampleStack(state);
|
||||
}
|
||||
ResumeThread(profiled_thread);
|
||||
}
|
||||
|
||||
#endif // USE_SIGNALS
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
Loading…
Reference in New Issue
Block a user