Index: src/sampler.cc |
diff --git a/src/sampler.cc b/src/sampler.cc |
index d779152ddbc9fa0cb42b8ad528e9e91c9827e32a..91f1bb0ddbfd59761ea4d6db3c8661d181f85ff1 100644 |
--- a/src/sampler.cc |
+++ b/src/sampler.cc |
@@ -25,6 +25,8 @@ |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+#include "sampler.h" |
+ |
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ |
|| defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__) \ |
|| defined(__native_client__) |
@@ -60,6 +62,8 @@ |
#include "v8.h" |
+#include "cpu-profiler.h" |
+#include "flags.h" |
#include "frames-inl.h" |
#include "log.h" |
#include "platform.h" |
@@ -230,30 +234,25 @@ class Sampler::PlatformData : public PlatformDataCommon { |
#endif |
-class SampleHelper { |
- public: |
- inline TickSample* Init(Sampler* sampler, Isolate* isolate) { |
#if defined(USE_SIMULATOR) |
+class SimulatorHelper { |
+ public: |
+ inline bool Init(Sampler* sampler, Isolate* isolate) { |
ThreadId thread_id = sampler->platform_data()->profiled_thread_id(); |
Isolate::PerIsolateThreadData* per_thread_data = isolate-> |
FindPerThreadDataForThread(thread_id); |
- if (!per_thread_data) return NULL; |
+ if (!per_thread_data) return false; |
simulator_ = per_thread_data->simulator(); |
- // Check if there is active simulator before allocating TickSample. |
- if (!simulator_) return NULL; |
-#endif // USE_SIMULATOR |
- TickSample* sample = isolate->cpu_profiler()->TickSampleEvent(); |
- if (sample == NULL) sample = &sample_obj; |
- return sample; |
+ // Check if there is active simulator. |
+ return simulator_ != NULL; |
} |
-#if defined(USE_SIMULATOR) |
- inline void FillRegisters(TickSample* sample) { |
+ inline void FillRegisters(RegisterState* state) { |
#if V8_TARGET_ARCH_ARM |
- sample->pc = reinterpret_cast<Address>(simulator_->get_pc()); |
- sample->sp = reinterpret_cast<Address>(simulator_->get_register( |
+ state->pc = reinterpret_cast<Address>(simulator_->get_pc()); |
+ state->sp = reinterpret_cast<Address>(simulator_->get_register( |
Simulator::sp)); |
- sample->fp = reinterpret_cast<Address>(simulator_->get_register( |
+ state->fp = reinterpret_cast<Address>(simulator_->get_register( |
Simulator::r11)); |
#elif V8_TARGET_ARCH_A64 |
if (simulator_->sp() == 0 || simulator_->fp() == 0) { |
@@ -263,25 +262,22 @@ class SampleHelper { |
// Bailout if sp/fp doesn't contain the new value. |
return; |
} |
- sample->pc = reinterpret_cast<Address>(simulator_->pc()); |
- sample->sp = reinterpret_cast<Address>(simulator_->sp()); |
- sample->fp = reinterpret_cast<Address>(simulator_->fp()); |
+ state->pc = reinterpret_cast<Address>(simulator_->pc()); |
+ state->sp = reinterpret_cast<Address>(simulator_->sp()); |
+ state->fp = reinterpret_cast<Address>(simulator_->fp()); |
#elif V8_TARGET_ARCH_MIPS |
- sample->pc = reinterpret_cast<Address>(simulator_->get_pc()); |
- sample->sp = reinterpret_cast<Address>(simulator_->get_register( |
+ state->pc = reinterpret_cast<Address>(simulator_->get_pc()); |
+ state->sp = reinterpret_cast<Address>(simulator_->get_register( |
Simulator::sp)); |
- sample->fp = reinterpret_cast<Address>(simulator_->get_register( |
+ state->fp = reinterpret_cast<Address>(simulator_->get_register( |
Simulator::fp)); |
#endif |
} |
-#endif // USE_SIMULATOR |
private: |
-#if defined(USE_SIMULATOR) |
Simulator* simulator_; |
-#endif |
- TickSample sample_obj; |
}; |
+#endif // USE_SIMULATOR |
#if defined(USE_SIGNALS) |
@@ -341,43 +337,42 @@ void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, |
Sampler* sampler = isolate->logger()->sampler(); |
if (sampler == NULL || !sampler->IsActive()) return; |
- SampleHelper helper; |
- TickSample* sample = helper.Init(sampler, isolate); |
- if (sample == NULL) return; |
+ RegisterState state; |
#if defined(USE_SIMULATOR) |
- helper.FillRegisters(sample); |
+ SimulatorHelper helper; |
+ if (!helper.Init(sampler, isolate)) return; |
+ helper.FillRegisters(&state); |
// It possible that the simulator is interrupted while it is updating |
// the sp or fp register. A64 simulator does this in two steps: |
// first setting it to zero and then setting it to the new value. |
// Bailout if sp/fp doesn't contain the new value. |
- if (sample->sp == 0 || sample->fp == 0) return; |
+ if (state.sp == 0 || state.fp == 0) return; |
#else |
// Extracting the sample from the context is extremely machine dependent. |
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
mcontext_t& mcontext = ucontext->uc_mcontext; |
- sample->state = isolate->current_vm_state(); |
#if defined(__linux__) || defined(__ANDROID__) |
#if V8_HOST_ARCH_IA32 |
- sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); |
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); |
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]); |
+ state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); |
+ state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); |
+ state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]); |
#elif V8_HOST_ARCH_X64 |
- sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]); |
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]); |
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]); |
+ state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]); |
+ state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]); |
+ state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]); |
#elif V8_HOST_ARCH_ARM |
#if defined(__GLIBC__) && !defined(__UCLIBC__) && \ |
(__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) |
// Old GLibc ARM versions used a gregs[] array to access the register |
// values from mcontext_t. |
- sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]); |
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]); |
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]); |
+ state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]); |
+ state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]); |
+ state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]); |
#else |
- sample->pc = reinterpret_cast<Address>(mcontext.arm_pc); |
- sample->sp = reinterpret_cast<Address>(mcontext.arm_sp); |
- sample->fp = reinterpret_cast<Address>(mcontext.arm_fp); |
+ state.pc = reinterpret_cast<Address>(mcontext.arm_pc); |
+ state.sp = reinterpret_cast<Address>(mcontext.arm_sp); |
+ state.fp = reinterpret_cast<Address>(mcontext.arm_fp); |
#endif // defined(__GLIBC__) && !defined(__UCLIBC__) && |
// (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) |
#elif V8_HOST_ARCH_A64 |
@@ -386,54 +381,52 @@ void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, |
// FP is an alias for x29. |
sample->fp = reinterpret_cast<Address>(mcontext.regs[29]); |
#elif V8_HOST_ARCH_MIPS |
- sample->pc = reinterpret_cast<Address>(mcontext.pc); |
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[29]); |
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[30]); |
+ state.pc = reinterpret_cast<Address>(mcontext.pc); |
+ state.sp = reinterpret_cast<Address>(mcontext.gregs[29]); |
+ state.fp = reinterpret_cast<Address>(mcontext.gregs[30]); |
#endif // V8_HOST_ARCH_* |
#elif defined(__FreeBSD__) |
#if V8_HOST_ARCH_IA32 |
- sample->pc = reinterpret_cast<Address>(mcontext.mc_eip); |
- sample->sp = reinterpret_cast<Address>(mcontext.mc_esp); |
- sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp); |
+ state.pc = reinterpret_cast<Address>(mcontext.mc_eip); |
+ state.sp = reinterpret_cast<Address>(mcontext.mc_esp); |
+ state.fp = reinterpret_cast<Address>(mcontext.mc_ebp); |
#elif V8_HOST_ARCH_X64 |
- sample->pc = reinterpret_cast<Address>(mcontext.mc_rip); |
- sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp); |
- sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp); |
+ state.pc = reinterpret_cast<Address>(mcontext.mc_rip); |
+ state.sp = reinterpret_cast<Address>(mcontext.mc_rsp); |
+ state.fp = reinterpret_cast<Address>(mcontext.mc_rbp); |
#elif V8_HOST_ARCH_ARM |
- sample->pc = reinterpret_cast<Address>(mcontext.mc_r15); |
- sample->sp = reinterpret_cast<Address>(mcontext.mc_r13); |
- sample->fp = reinterpret_cast<Address>(mcontext.mc_r11); |
+ state.pc = reinterpret_cast<Address>(mcontext.mc_r15); |
+ state.sp = reinterpret_cast<Address>(mcontext.mc_r13); |
+ state.fp = reinterpret_cast<Address>(mcontext.mc_r11); |
#endif // V8_HOST_ARCH_* |
#elif defined(__NetBSD__) |
#if V8_HOST_ARCH_IA32 |
- sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]); |
- sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]); |
- sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]); |
+ state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]); |
+ state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]); |
+ state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]); |
#elif V8_HOST_ARCH_X64 |
- sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]); |
- sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]); |
- sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]); |
+ state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]); |
+ state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]); |
+ state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]); |
#endif // V8_HOST_ARCH_* |
#elif defined(__OpenBSD__) |
USE(mcontext); |
#if V8_HOST_ARCH_IA32 |
- sample->pc = reinterpret_cast<Address>(ucontext->sc_eip); |
- sample->sp = reinterpret_cast<Address>(ucontext->sc_esp); |
- sample->fp = reinterpret_cast<Address>(ucontext->sc_ebp); |
+ state.pc = reinterpret_cast<Address>(ucontext->sc_eip); |
+ state.sp = reinterpret_cast<Address>(ucontext->sc_esp); |
+ state.fp = reinterpret_cast<Address>(ucontext->sc_ebp); |
#elif V8_HOST_ARCH_X64 |
- sample->pc = reinterpret_cast<Address>(ucontext->sc_rip); |
- sample->sp = reinterpret_cast<Address>(ucontext->sc_rsp); |
- sample->fp = reinterpret_cast<Address>(ucontext->sc_rbp); |
+ state.pc = reinterpret_cast<Address>(ucontext->sc_rip); |
+ state.sp = reinterpret_cast<Address>(ucontext->sc_rsp); |
+ state.fp = reinterpret_cast<Address>(ucontext->sc_rbp); |
#endif // V8_HOST_ARCH_* |
#elif defined(__sun) |
- sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); |
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); |
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); |
+ state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); |
+ state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); |
+ state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); |
#endif // __sun |
#endif // USE_SIMULATOR |
- |
- sampler->SampleStack(sample); |
- sampler->Tick(sample); |
+ sampler->SampleStack(state); |
#endif // __native_client__ |
} |
@@ -530,17 +523,18 @@ class SamplerThread : public Thread { |
void SampleContext(Sampler* sampler) { |
thread_act_t profiled_thread = sampler->platform_data()->profiled_thread(); |
- Isolate* isolate = sampler->isolate(); |
- SampleHelper helper; |
- TickSample* sample = helper.Init(sampler, isolate); |
- if (sample == NULL) return; |
+#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 state; |
+ 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 |
@@ -549,7 +543,7 @@ class SamplerThread : public Thread { |
#endif // __DARWIN_UNIX03 |
#elif V8_HOST_ARCH_IA32 |
thread_state_flavor_t flavor = i386_THREAD_STATE; |
- i386_thread_state_t 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 |
@@ -562,19 +556,18 @@ class SamplerThread : public Thread { |
if (thread_get_state(profiled_thread, |
flavor, |
- reinterpret_cast<natural_t*>(&state), |
+ reinterpret_cast<natural_t*>(&thread_state), |
&count) == KERN_SUCCESS) { |
- sample->state = isolate->current_vm_state(); |
+ RegisterState state; |
#if defined(USE_SIMULATOR) |
- helper.FillRegisters(sample); |
+ helper.FillRegisters(&state); |
#else |
- sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip)); |
- sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp)); |
- sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp)); |
+ 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(sample); |
- sampler->Tick(sample); |
+ sampler->SampleStack(state); |
} |
thread_resume(profiled_thread); |
} |
@@ -586,34 +579,34 @@ class SamplerThread : public Thread { |
if (profiled_thread == NULL) return; |
Isolate* isolate = sampler->isolate(); |
- SampleHelper helper; |
- TickSample* sample = helper.Init(sampler, isolate); |
- if (sample == NULL) return; |
+#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; |
- sample->state = isolate->current_vm_state(); |
// 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(sample); |
+ helper.FillRegisters(&state); |
#else |
#if V8_HOST_ARCH_X64 |
- sample->pc = reinterpret_cast<Address>(context.Rip); |
- sample->sp = reinterpret_cast<Address>(context.Rsp); |
- sample->fp = reinterpret_cast<Address>(context.Rbp); |
+ state.pc = reinterpret_cast<Address>(context.Rip); |
+ state.sp = reinterpret_cast<Address>(context.Rsp); |
+ state.fp = reinterpret_cast<Address>(context.Rbp); |
#else |
- sample->pc = reinterpret_cast<Address>(context.Eip); |
- sample->sp = reinterpret_cast<Address>(context.Esp); |
- sample->fp = reinterpret_cast<Address>(context.Ebp); |
+ 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(sample); |
- sampler->Tick(sample); |
+ sampler->SampleStack(state); |
} |
ResumeThread(profiled_thread); |
} |
@@ -639,8 +632,11 @@ SamplerThread* SamplerThread::instance_ = NULL; |
// |
// StackTracer implementation |
// |
-DISABLE_ASAN void TickSample::Trace(Isolate* isolate) { |
+DISABLE_ASAN void TickSample::Init(Isolate* isolate, |
+ const RegisterState& regs) { |
ASSERT(isolate->IsInitialized()); |
+ pc = regs.pc; |
+ state = isolate->current_vm_state(); |
// Avoid collecting traces while doing GC. |
if (state == GC) return; |
@@ -659,11 +655,12 @@ DISABLE_ASAN void TickSample::Trace(Isolate* isolate) { |
} else { |
// Sample potential return address value for frameless invocation of |
// stubs (we'll figure out later, if this value makes sense). |
- tos = Memory::Address_at(sp); |
+ tos = Memory::Address_at(regs.sp); |
has_external_callback = false; |
} |
- SafeStackFrameIterator it(isolate, fp, sp, sp, js_entry_sp); |
+ SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp); |
+ top_frame_type = it.top_frame_type(); |
int i = 0; |
while (!it.done() && i < TickSample::kMaxFramesCount) { |
stack[i++] = it.frame()->pc(); |
@@ -698,6 +695,7 @@ Sampler::~Sampler() { |
delete data_; |
} |
+ |
void Sampler::Start() { |
ASSERT(!IsActive()); |
SetActive(true); |
@@ -711,9 +709,14 @@ void Sampler::Stop() { |
SetActive(false); |
} |
-void Sampler::SampleStack(TickSample* sample) { |
- sample->Trace(isolate_); |
+ |
+void Sampler::SampleStack(const RegisterState& state) { |
+ TickSample* sample = isolate_->cpu_profiler()->TickSampleEvent(); |
+ TickSample sample_obj; |
+ if (sample == NULL) sample = &sample_obj; |
+ sample->Init(isolate_, state); |
if (++samples_taken_ < 0) samples_taken_ = 0; |
+ Tick(sample); |
} |
} } // namespace v8::internal |