Chromium Code Reviews| Index: runtime/vm/profiler.cc |
| diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc |
| index d8bed39239c2c90222bb80d9005561308f1e1b5b..4498d0069389de9ccc4ef6cd9603838c6da575a7 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,54 +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; |
| @@ -160,13 +114,11 @@ void Profiler::BeginExecution(Isolate* isolate) { |
| return; |
| } |
| ASSERT(initialized_); |
| - IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| - if (profiler_data == NULL) { |
| + Thread* thread = Thread::Current(); |
| + if (thread == NULL) { |
| return; |
| } |
| - Thread* thread = Thread::Current(); |
| - thread->SetThreadInterrupter(RecordSampleInterruptCallback, thread); |
| - ThreadInterrupter::WakeUp(); |
| + thread->SetThreadInterruptCallback(SampleThreadInterruptCallback); |
| } |
| @@ -179,42 +131,7 @@ void Profiler::EndExecution(Isolate* isolate) { |
| } |
| 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(); |
| - } |
| + thread->SetThreadInterruptCallback(NULL); |
|
Ivan Posva
2015/10/28 08:27:47
It looks like we have several redundant ways of di
|
| } |
| @@ -817,10 +734,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 +768,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 +781,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 +824,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 +841,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 +870,7 @@ static bool CheckIsolate(Isolate* isolate) { |
| // No isolate. |
| return false; |
| } |
| - ASSERT(isolate != Dart::vm_isolate()); |
| - return true; |
| + return isolate != Dart::vm_isolate(); |
| } |
| @@ -997,16 +886,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(); |
|
Ivan Posva
2015/10/28 08:27:47
Shouldn't this be an assert? The thread has better
Cutch
2015/10/28 14:39:19
This is called from Object::Allocate which means w
|
| - SampleBuffer* sample_buffer = GetSampleBuffer(isolate); |
| + SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
| if (sample_buffer == NULL) { |
| // Profiler not initialized. |
| return; |
| @@ -1022,13 +911,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 +960,46 @@ 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. |
| + if (!CheckIsolate(isolate)) { |
| return; |
| } |
| - ASSERT(isolate != Dart::vm_isolate()); |
| - SampleBuffer* sample_buffer = GetSampleBuffer(isolate); |
| - if (sample_buffer == NULL) { |
| - // Profiler not initialized. |
| + if (!thread->IsMutatorThread()) { |
| + // Not a mutator thread. |
| + // TODO(johnmccutchan): Profile all threads with an 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 (isolate->HasDebugger()) { |
|
Ivan Posva
2015/10/28 08:27:47
Please add a comment that this is really only rele
Cutch
2015/10/28 14:39:18
Done.
|
| + Debugger* debugger = isolate->debugger(); |
| + if (debugger->IsPaused()) { |
| + // Mutator is paused at breakpoint. |
| + return; |
| + } |
| } |
| - if (!InitialRegisterCheck(pc, sp, fp)) { |
| + MessageHandler* msg_handler = isolate->message_handler(); |
|
Ivan Posva
2015/10/28 08:27:47
This and the debugger check are only relevant for
Cutch
2015/10/28 14:39:18
I've factored both of these checks into a helper f
|
| + if ((msg_handler != NULL) && |
| + (msg_handler->paused_on_start() || |
| + msg_handler->paused_on_exit())) { |
| + // Isolate is paused at start / exit. |
| 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. |
| - return; |
| - } |
| + const bool exited_dart_code = thread->HasExitedDartCode(); |
|
Ivan Posva
2015/10/28 08:27:47
Is there any particular reason why this should be
Cutch
2015/10/28 14:39:19
No. Moved down closer to their use.
|
| + const bool in_dart_code = thread->IsExecutingDartCode(); |
| 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 +1008,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, |
| @@ -1184,6 +1060,49 @@ void Profiler::RecordSampleInterruptCallback( |
| } |
| +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); |