Index: runtime/vm/profiler.cc |
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc |
index d8bed39239c2c90222bb80d9005561308f1e1b5b..1084d7eef9f5be384a32cc2590dde6ae488f57fb 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,64 +931,32 @@ void Profiler::RecordAllocation(Thread* thread, intptr_t cid) { |
} |
-void Profiler::RecordSampleInterruptCallback( |
- const InterruptedThreadState& state, |
- void* data) { |
- Thread* thread = reinterpret_cast<Thread*>(data); |
+void Profiler::SampleThread(Thread* thread, |
+ uintptr_t pc, |
+ uintptr_t fp, |
+ uintptr_t sp) { |
+ ASSERT(thread != NULL); |
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. |
+ if (!CheckIsolate(isolate)) { |
return; |
} |
- const bool exited_dart_code = ExitedDart(thread); |
- const bool in_dart_code = ExecutingDart(thread); |
- |
- uintptr_t sp = 0; |
- uintptr_t fp = state.fp; |
- uintptr_t pc = state.pc; |
-#if defined(USING_SIMULATOR) |
- Simulator* simulator = NULL; |
-#endif |
- |
- if (in_dart_code) { |
- // If we're in Dart code, use the Dart stack pointer. |
-#if defined(USING_SIMULATOR) |
- simulator = isolate->simulator(); |
- sp = simulator->get_register(SPREG); |
- fp = simulator->get_register(FPREG); |
- pc = simulator->get_pc(); |
-#else |
- sp = state.dsp; |
-#endif |
- } else { |
- // If we're in runtime code, use the C stack pointer. |
- sp = state.csp; |
- } |
- |
- if (!InitialRegisterCheck(pc, sp, fp)) { |
+ if (!thread->IsMutatorThread()) { |
+ // Not a mutator thread. |
+ // TODO(johnmccutchan): Profile all threads with an isolate. |
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. |
+ if (!ShouldSampleMutator(thread, isolate)) { |
+ // Mutator shouldn't be sampled. |
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 +965,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 +1003,9 @@ void Profiler::RecordSampleInterruptCallback( |
fp, |
sp); |
+ const bool exited_dart_code = thread->HasExitedDartCode(); |
+ const bool in_dart_code = thread->IsExecutingDartCode(); |
+ |
// All memory access is done inside CollectSample. |
CollectSample(isolate, |
exited_dart_code, |
@@ -1184,6 +1020,76 @@ void Profiler::RecordSampleInterruptCallback( |
} |
+bool Profiler::ShouldSampleMutator(Thread* thread, Isolate* isolate) { |
+ ASSERT(thread != NULL); |
+ ASSERT(isolate != NULL); |
+ |
+ // During isolate initialization we may get a tick before the debugger has |
+ // been setup. |
+ if (isolate->HasDebugger()) { |
+ Debugger* debugger = isolate->debugger(); |
+ if (debugger->IsPaused()) { |
Ivan Posva
2015/10/28 19:31:53
Is this still needed given the fact that the debug
Cutch
2015/10/28 19:50:33
This whole function is now gone.
|
+ // Mutator is paused at breakpoint. |
+ return false; |
+ } |
+ } |
+ |
+ // Similarly, we might get a tick before the message handler is setup. |
+ MessageHandler* msg_handler = isolate->message_handler(); |
+ if ((msg_handler != NULL) && |
+ (msg_handler->paused_on_start() || |
Ivan Posva
2015/10/28 19:31:53
If the isolate is paused on start/exit then it is
Cutch
2015/10/28 19:50:33
Done.
|
+ msg_handler->paused_on_exit())) { |
+ // Isolate is paused at start / exit. |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+ |
+void Profiler::SampleThreadInterruptCallback( |
+ Thread* thread, |
+ const InterruptedThreadState& state) { |
+ const bool in_dart_code = thread->IsExecutingDartCode(); |
+ |
+ uintptr_t sp = 0; |
+ uintptr_t fp = state.fp; |
+ uintptr_t pc = state.pc; |
+#if defined(USING_SIMULATOR) |
+ Simulator* simulator = NULL; |
+#endif |
+ |
+ if (StubCode::HasBeenInitialized() && |
+ 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; |
+ } |
+ |
+ if (in_dart_code) { |
+ // If we're in Dart code, use the Dart stack pointer. |
+#if defined(USING_SIMULATOR) |
+ simulator = isolate->simulator(); |
+ sp = simulator->get_register(SPREG); |
+ fp = simulator->get_register(FPREG); |
+ pc = simulator->get_pc(); |
+#else |
+ sp = state.dsp; |
+#endif |
+ } else { |
+ // If we're in runtime code, use the C stack pointer. |
+ sp = state.csp; |
+ } |
+ |
+ if (!InitialRegisterCheck(pc, fp, sp)) { |
+ return; |
+ } |
+ |
+ SampleThread(thread, pc, fp, sp); |
+} |
+ |
+ |
ProcessedSampleBuffer* SampleBuffer::BuildProcessedSampleBuffer( |
SampleFilter* filter) { |
ASSERT(filter != NULL); |