| Index: runtime/vm/profiler.cc
|
| diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
|
| index d8bed39239c2c90222bb80d9005561308f1e1b5b..3773df5cf9b8cb9185d3a33f9d46c38a7e151755 100644
|
| --- a/runtime/vm/profiler.cc
|
| +++ b/runtime/vm/profiler.cc
|
| @@ -9,10 +9,12 @@
|
| #include "vm/allocation.h"
|
| #include "vm/atomic.h"
|
| #include "vm/code_patcher.h"
|
| +#include "vm/debugger.h"
|
| #include "vm/instructions.h"
|
| #include "vm/isolate.h"
|
| #include "vm/json_stream.h"
|
| #include "vm/lockers.h"
|
| +#include "vm/message_handler.h"
|
| #include "vm/native_symbol.h"
|
| #include "vm/object.h"
|
| #include "vm/os.h"
|
| @@ -104,120 +106,6 @@ void Profiler::SetSamplePeriod(intptr_t period) {
|
| }
|
|
|
|
|
| -void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) {
|
| - if (!FLAG_profile) {
|
| - return;
|
| - }
|
| - ASSERT(isolate == Isolate::Current());
|
| - ASSERT(isolate != NULL);
|
| - ASSERT(sample_buffer_ != NULL);
|
| - {
|
| - MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
|
| - SampleBuffer* sample_buffer = sample_buffer_;
|
| - if (!shared_buffer) {
|
| - sample_buffer = new SampleBuffer();
|
| - }
|
| - IsolateProfilerData* profiler_data =
|
| - new IsolateProfilerData(sample_buffer, !shared_buffer);
|
| - ASSERT(profiler_data != NULL);
|
| - isolate->set_profiler_data(profiler_data);
|
| - if (FLAG_trace_profiled_isolates) {
|
| - OS::Print("Profiler Setup %p %s\n", isolate, isolate->name());
|
| - }
|
| - }
|
| - BeginExecution(isolate);
|
| -}
|
| -
|
| -
|
| -void Profiler::ShutdownProfilingForIsolate(Isolate* isolate) {
|
| - ASSERT(isolate != NULL);
|
| - if (!FLAG_profile) {
|
| - return;
|
| - }
|
| - // We do not have a current isolate.
|
| - ASSERT(Isolate::Current() == NULL);
|
| - {
|
| - MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
|
| - IsolateProfilerData* profiler_data = isolate->profiler_data();
|
| - if (profiler_data == NULL) {
|
| - // Already freed.
|
| - return;
|
| - }
|
| - isolate->set_profiler_data(NULL);
|
| - delete profiler_data;
|
| - if (FLAG_trace_profiled_isolates) {
|
| - OS::Print("Profiler Shutdown %p %s\n", isolate, isolate->name());
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -void Profiler::BeginExecution(Isolate* isolate) {
|
| - if (isolate == NULL) {
|
| - return;
|
| - }
|
| - if (!FLAG_profile) {
|
| - return;
|
| - }
|
| - ASSERT(initialized_);
|
| - IsolateProfilerData* profiler_data = isolate->profiler_data();
|
| - if (profiler_data == NULL) {
|
| - return;
|
| - }
|
| - Thread* thread = Thread::Current();
|
| - thread->SetThreadInterrupter(RecordSampleInterruptCallback, thread);
|
| - ThreadInterrupter::WakeUp();
|
| -}
|
| -
|
| -
|
| -void Profiler::EndExecution(Isolate* isolate) {
|
| - if (isolate == NULL) {
|
| - return;
|
| - }
|
| - if (!FLAG_profile) {
|
| - return;
|
| - }
|
| - ASSERT(initialized_);
|
| - Thread* thread = Thread::Current();
|
| - thread->SetThreadInterrupter(NULL, NULL);
|
| -}
|
| -
|
| -
|
| -IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer,
|
| - bool own_sample_buffer) {
|
| - ASSERT(sample_buffer != NULL);
|
| - sample_buffer_ = sample_buffer;
|
| - own_sample_buffer_ = own_sample_buffer;
|
| - block_count_ = 0;
|
| -}
|
| -
|
| -
|
| -IsolateProfilerData::~IsolateProfilerData() {
|
| - if (own_sample_buffer_) {
|
| - delete sample_buffer_;
|
| - sample_buffer_ = NULL;
|
| - own_sample_buffer_ = false;
|
| - }
|
| -}
|
| -
|
| -
|
| -void IsolateProfilerData::Block() {
|
| - block_count_++;
|
| -}
|
| -
|
| -
|
| -void IsolateProfilerData::Unblock() {
|
| - block_count_--;
|
| - if (block_count_ < 0) {
|
| - FATAL("Too many calls to Dart_IsolateUnblocked.");
|
| - }
|
| - if (!blocked()) {
|
| - // We just unblocked this isolate, wake up the thread interrupter.
|
| - ThreadInterrupter::WakeUp();
|
| - }
|
| -}
|
| -
|
| -
|
| intptr_t Sample::pcs_length_ = 0;
|
| intptr_t Sample::instance_size_ = 0;
|
|
|
| @@ -817,10 +705,10 @@ static void CollectSample(Isolate* isolate,
|
| if (FLAG_profile_vm) {
|
| // Always walk the native stack collecting both native and Dart frames.
|
| native_stack_walker->walk();
|
| - } else if (exited_dart_code) {
|
| + } else if (StubCode::HasBeenInitialized() && exited_dart_code) {
|
| // We have a valid exit frame info, use the Dart stack walker.
|
| dart_exit_stack_walker->walk();
|
| - } else if (in_dart_code) {
|
| + } else if (StubCode::HasBeenInitialized() && in_dart_code) {
|
| // We are executing Dart code. We have frame pointers.
|
| dart_stack_walker->walk();
|
| } else {
|
| @@ -851,26 +739,11 @@ static void CollectSample(Isolate* isolate,
|
| }
|
|
|
|
|
| -// Is |thread| executing Dart code?
|
| -static bool ExecutingDart(Thread* thread) {
|
| - ASSERT(thread != NULL);
|
| - return (thread->top_exit_frame_info() == 0) &&
|
| - (thread->vm_tag() == VMTag::kDartTagId);
|
| -}
|
| -
|
| -
|
| -// Has |thread| exited Dart code?
|
| -static bool ExitedDart(Thread* thread) {
|
| - return (thread->top_exit_frame_info() != 0) &&
|
| - (thread->vm_tag() != VMTag::kDartTagId);
|
| -}
|
| -
|
| -
|
| // Get |isolate|'s stack boundary and verify that |sp| and |fp| are within
|
| // it. Return |false| if anything looks suspicious.
|
| static bool GetAndValidateIsolateStackBounds(Thread* thread,
|
| - uintptr_t sp,
|
| uintptr_t fp,
|
| + uintptr_t sp,
|
| uword* stack_lower,
|
| uword* stack_upper) {
|
| ASSERT(thread != NULL);
|
| @@ -879,7 +752,7 @@ static bool GetAndValidateIsolateStackBounds(Thread* thread,
|
| ASSERT(stack_lower != NULL);
|
| ASSERT(stack_upper != NULL);
|
| #if defined(USING_SIMULATOR)
|
| - const bool in_dart_code = ExecutingDart(thread);
|
| + const bool in_dart_code = thread->IsExecutingDartCode();
|
| if (in_dart_code) {
|
| Simulator* simulator = isolate->simulator();
|
| *stack_lower = simulator->StackBase();
|
| @@ -922,8 +795,8 @@ static bool GetAndValidateIsolateStackBounds(Thread* thread,
|
| }
|
|
|
|
|
| -// Some simple sanity checking of |pc|, |sp|, and |fp|.
|
| -static bool InitialRegisterCheck(uintptr_t pc, uintptr_t sp, uintptr_t fp) {
|
| +// Some simple sanity checking of |pc|, |fp|, and |sp|.
|
| +static bool InitialRegisterCheck(uintptr_t pc, uintptr_t fp, uintptr_t sp) {
|
| if ((sp == 0) || (fp == 0) || (pc == 0)) {
|
| // None of these registers should be zero.
|
| return false;
|
| @@ -939,18 +812,6 @@ static bool InitialRegisterCheck(uintptr_t pc, uintptr_t sp, uintptr_t fp) {
|
| }
|
|
|
|
|
| -// Return |isolate|'s sample buffer.
|
| -static SampleBuffer* GetSampleBuffer(Isolate* isolate) {
|
| - IsolateProfilerData* profiler_data = isolate->profiler_data();
|
| - if (profiler_data == NULL) {
|
| - // Profiler not initialized.
|
| - return NULL;
|
| - }
|
| - SampleBuffer* sample_buffer = profiler_data->sample_buffer();
|
| - return sample_buffer;
|
| -}
|
| -
|
| -
|
| static Sample* SetupSample(Thread* thread,
|
| SampleBuffer* sample_buffer,
|
| ThreadId tid) {
|
| @@ -980,8 +841,7 @@ static bool CheckIsolate(Isolate* isolate) {
|
| // No isolate.
|
| return false;
|
| }
|
| - ASSERT(isolate != Dart::vm_isolate());
|
| - return true;
|
| + return isolate != Dart::vm_isolate();
|
| }
|
|
|
|
|
| @@ -997,16 +857,16 @@ static uintptr_t __attribute__((noinline)) GetProgramCounter() {
|
| }
|
| #endif
|
|
|
| -void Profiler::RecordAllocation(Thread* thread, intptr_t cid) {
|
| +void Profiler::SampleAllocation(Thread* thread, intptr_t cid) {
|
| ASSERT(thread != NULL);
|
| Isolate* isolate = thread->isolate();
|
| if (!CheckIsolate(isolate)) {
|
| return;
|
| }
|
|
|
| - const bool exited_dart_code = ExitedDart(thread);
|
| + const bool exited_dart_code = thread->HasExitedDartCode();
|
|
|
| - SampleBuffer* sample_buffer = GetSampleBuffer(isolate);
|
| + SampleBuffer* sample_buffer = Profiler::sample_buffer();
|
| if (sample_buffer == NULL) {
|
| // Profiler not initialized.
|
| return;
|
| @@ -1022,13 +882,13 @@ void Profiler::RecordAllocation(Thread* thread, intptr_t cid) {
|
| uword stack_lower = 0;
|
| uword stack_upper = 0;
|
|
|
| - if (!InitialRegisterCheck(pc, sp, fp)) {
|
| + if (!InitialRegisterCheck(pc, fp, sp)) {
|
| return;
|
| }
|
|
|
| if (!GetAndValidateIsolateStackBounds(thread,
|
| - sp,
|
| fp,
|
| + sp,
|
| &stack_lower,
|
| &stack_upper)) {
|
| // Could not get stack boundary.
|
| @@ -1071,25 +931,17 @@ void Profiler::RecordAllocation(Thread* thread, intptr_t cid) {
|
| }
|
|
|
|
|
| -void Profiler::RecordSampleInterruptCallback(
|
| - const InterruptedThreadState& state,
|
| - void* data) {
|
| - Thread* thread = reinterpret_cast<Thread*>(data);
|
| - Isolate* isolate = thread->isolate();
|
| - if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) {
|
| - // No isolate.
|
| - return;
|
| - }
|
| - ASSERT(isolate != Dart::vm_isolate());
|
| -
|
| - SampleBuffer* sample_buffer = GetSampleBuffer(isolate);
|
| - if (sample_buffer == NULL) {
|
| - // Profiler not initialized.
|
| +void Profiler::SampleThread(Thread* thread,
|
| + const InterruptedThreadState& state) {
|
| + if (StubCode::HasBeenInitialized() &&
|
| + StubCode::InJumpToExceptionHandlerStub(state.pc)) {
|
| + // The JumpToExceptionHandler stub manually adjusts the stack pointer,
|
| + // frame pointer, and some isolate state before jumping to a catch entry.
|
| + // It is not safe to walk the stack when executing this stub.
|
| return;
|
| }
|
|
|
| - const bool exited_dart_code = ExitedDart(thread);
|
| - const bool in_dart_code = ExecutingDart(thread);
|
| + const bool in_dart_code = thread->IsExecutingDartCode();
|
|
|
| uintptr_t sp = 0;
|
| uintptr_t fp = state.fp;
|
| @@ -1113,22 +965,27 @@ void Profiler::RecordSampleInterruptCallback(
|
| sp = state.csp;
|
| }
|
|
|
| - if (!InitialRegisterCheck(pc, sp, fp)) {
|
| + if (!InitialRegisterCheck(pc, fp, sp)) {
|
| return;
|
| }
|
|
|
| - if (StubCode::InJumpToExceptionHandlerStub(pc)) {
|
| - // The JumpToExceptionHandler stub manually adjusts the stack pointer,
|
| - // frame pointer, and some isolate state before jumping to a catch entry.
|
| - // It is not safe to walk the stack when executing this stub.
|
| + ASSERT(thread != NULL);
|
| + Isolate* isolate = thread->isolate();
|
| + if (!CheckIsolate(isolate)) {
|
| + return;
|
| + }
|
| +
|
| + if (!thread->IsMutatorThread()) {
|
| + // Not a mutator thread.
|
| + // TODO(johnmccutchan): Profile all threads with an isolate.
|
| return;
|
| }
|
|
|
| uword stack_lower = 0;
|
| uword stack_upper = 0;
|
| if (!GetAndValidateIsolateStackBounds(thread,
|
| - sp,
|
| fp,
|
| + sp,
|
| &stack_lower,
|
| &stack_upper)) {
|
| // Could not get stack boundary.
|
| @@ -1137,6 +994,11 @@ void Profiler::RecordSampleInterruptCallback(
|
|
|
| // At this point we have a valid stack boundary for this isolate and
|
| // know that our initial stack and frame pointers are within the boundary.
|
| + SampleBuffer* sample_buffer = Profiler::sample_buffer();
|
| + if (sample_buffer == NULL) {
|
| + // Profiler not initialized.
|
| + return;
|
| + }
|
|
|
| // Setup sample.
|
| Sample* sample = SetupSample(thread,
|
| @@ -1170,6 +1032,8 @@ void Profiler::RecordSampleInterruptCallback(
|
| fp,
|
| sp);
|
|
|
| + const bool exited_dart_code = thread->HasExitedDartCode();
|
| +
|
| // All memory access is done inside CollectSample.
|
| CollectSample(isolate,
|
| exited_dart_code,
|
|
|