Index: runtime/vm/profiler.cc |
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc |
index 5307d996fd04be5da9542acd8ebbe7fcfbbf9cbe..d8bed39239c2c90222bb80d9005561308f1e1b5b 100644 |
--- a/runtime/vm/profiler.cc |
+++ b/runtime/vm/profiler.cc |
@@ -9,12 +9,10 @@ |
#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" |
@@ -106,6 +104,120 @@ 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; |
@@ -705,10 +817,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 (StubCode::HasBeenInitialized() && exited_dart_code) { |
+ } else if (exited_dart_code) { |
// We have a valid exit frame info, use the Dart stack walker. |
dart_exit_stack_walker->walk(); |
- } else if (StubCode::HasBeenInitialized() && in_dart_code) { |
+ } else if (in_dart_code) { |
// We are executing Dart code. We have frame pointers. |
dart_stack_walker->walk(); |
} else { |
@@ -739,11 +851,26 @@ 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 fp, |
uintptr_t sp, |
+ uintptr_t fp, |
uword* stack_lower, |
uword* stack_upper) { |
ASSERT(thread != NULL); |
@@ -752,7 +879,7 @@ static bool GetAndValidateIsolateStackBounds(Thread* thread, |
ASSERT(stack_lower != NULL); |
ASSERT(stack_upper != NULL); |
#if defined(USING_SIMULATOR) |
- const bool in_dart_code = thread->IsExecutingDartCode(); |
+ const bool in_dart_code = ExecutingDart(thread); |
if (in_dart_code) { |
Simulator* simulator = isolate->simulator(); |
*stack_lower = simulator->StackBase(); |
@@ -795,8 +922,8 @@ static bool GetAndValidateIsolateStackBounds(Thread* thread, |
} |
-// Some simple sanity checking of |pc|, |fp|, and |sp|. |
-static bool InitialRegisterCheck(uintptr_t pc, uintptr_t fp, uintptr_t sp) { |
+// Some simple sanity checking of |pc|, |sp|, and |fp|. |
+static bool InitialRegisterCheck(uintptr_t pc, uintptr_t sp, uintptr_t fp) { |
if ((sp == 0) || (fp == 0) || (pc == 0)) { |
// None of these registers should be zero. |
return false; |
@@ -812,6 +939,18 @@ static bool InitialRegisterCheck(uintptr_t pc, uintptr_t fp, uintptr_t sp) { |
} |
+// 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) { |
@@ -841,7 +980,8 @@ static bool CheckIsolate(Isolate* isolate) { |
// No isolate. |
return false; |
} |
- return isolate != Dart::vm_isolate(); |
+ ASSERT(isolate != Dart::vm_isolate()); |
+ return true; |
} |
@@ -857,16 +997,16 @@ static uintptr_t __attribute__((noinline)) GetProgramCounter() { |
} |
#endif |
-void Profiler::SampleAllocation(Thread* thread, intptr_t cid) { |
+void Profiler::RecordAllocation(Thread* thread, intptr_t cid) { |
ASSERT(thread != NULL); |
Isolate* isolate = thread->isolate(); |
if (!CheckIsolate(isolate)) { |
return; |
} |
- const bool exited_dart_code = thread->HasExitedDartCode(); |
+ const bool exited_dart_code = ExitedDart(thread); |
- SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
+ SampleBuffer* sample_buffer = GetSampleBuffer(isolate); |
if (sample_buffer == NULL) { |
// Profiler not initialized. |
return; |
@@ -882,13 +1022,13 @@ void Profiler::SampleAllocation(Thread* thread, intptr_t cid) { |
uword stack_lower = 0; |
uword stack_upper = 0; |
- if (!InitialRegisterCheck(pc, fp, sp)) { |
+ if (!InitialRegisterCheck(pc, sp, fp)) { |
return; |
} |
if (!GetAndValidateIsolateStackBounds(thread, |
- fp, |
sp, |
+ fp, |
&stack_lower, |
&stack_upper)) { |
// Could not get stack boundary. |
@@ -931,17 +1071,25 @@ void Profiler::SampleAllocation(Thread* thread, intptr_t cid) { |
} |
-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. |
+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()); |
- const bool in_dart_code = thread->IsExecutingDartCode(); |
+ SampleBuffer* sample_buffer = GetSampleBuffer(isolate); |
+ if (sample_buffer == NULL) { |
+ // Profiler not initialized. |
+ return; |
+ } |
+ |
+ const bool exited_dart_code = ExitedDart(thread); |
+ const bool in_dart_code = ExecutingDart(thread); |
uintptr_t sp = 0; |
uintptr_t fp = state.fp; |
@@ -950,9 +1098,6 @@ void Profiler::SampleThread(Thread* thread, |
Simulator* simulator = NULL; |
#endif |
- ASSERT(thread != NULL); |
- Isolate* isolate = thread->isolate(); |
- |
if (in_dart_code) { |
// If we're in Dart code, use the Dart stack pointer. |
#if defined(USING_SIMULATOR) |
@@ -968,25 +1113,22 @@ void Profiler::SampleThread(Thread* thread, |
sp = state.csp; |
} |
- if (!InitialRegisterCheck(pc, fp, sp)) { |
- return; |
- } |
- |
- if (!CheckIsolate(isolate)) { |
+ if (!InitialRegisterCheck(pc, sp, fp)) { |
return; |
} |
- if (!thread->IsMutatorThread()) { |
- // Not a mutator thread. |
- // TODO(johnmccutchan): Profile all threads with an isolate. |
+ 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. |
return; |
} |
uword stack_lower = 0; |
uword stack_upper = 0; |
if (!GetAndValidateIsolateStackBounds(thread, |
- fp, |
sp, |
+ fp, |
&stack_lower, |
&stack_upper)) { |
// Could not get stack boundary. |
@@ -995,11 +1137,6 @@ void Profiler::SampleThread(Thread* thread, |
// 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, |
@@ -1033,8 +1170,6 @@ void Profiler::SampleThread(Thread* thread, |
fp, |
sp); |
- const bool exited_dart_code = thread->HasExitedDartCode(); |
- |
// All memory access is done inside CollectSample. |
CollectSample(isolate, |
exited_dart_code, |