Chromium Code Reviews| Index: runtime/vm/profiler.cc |
| diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc |
| index d8ec5da69b8c6796a9570be71e38a0e308e84d52..6c5d0d747daf21c3b892c2ee9606c496dc5c8ece 100644 |
| --- a/runtime/vm/profiler.cc |
| +++ b/runtime/vm/profiler.cc |
| @@ -910,6 +910,95 @@ class CodeRegionTable : public ValueObject { |
| }; |
| +class FixTopFrameVisitor : public SampleVisitor { |
|
srdjan
2014/05/02 18:20:29
Make SampleVisitor a ValueObject if possible so th
Cutch
2014/05/02 18:37:03
Done.
|
| + public: |
| + explicit FixTopFrameVisitor(Isolate* isolate) |
| + : SampleVisitor(isolate), |
| + code_(Code::Handle(isolate)), |
| + vm_isolate_(Dart::vm_isolate()) { |
| + } |
| + |
| + void VisitSample(Sample* sample) { |
| + if (sample->processed()) { |
| + // Already processed. |
| + return; |
| + } |
| + // Mark that we've processed this sample. |
| + sample->set_processed(true); |
| + // Lookup code object for leaf frame. |
| + code_ = FindCodeForPC(sample->At(0)); |
| + sample->set_leaf_frame_is_dart(!code_.IsNull()); |
| + if (!code_.IsNull() && (code_.compile_timestamp() > sample->timestamp())) { |
| + // Code compiled after sample. Ignore. |
| + return; |
| + } |
| + if (sample->leaf_frame_is_dart()) { |
| + FixMissingDartFrame(sample); |
| + } |
| + } |
| + |
| + private: |
| + void FixMissingDartFrame(Sample* sample) { |
|
srdjan
2014/05/02 18:20:29
s/FixMissingDartFrame/CheckForMissingDartFrame/
Cutch
2014/05/02 18:37:03
Done.
|
| + // Some stubs (and intrinsics) do not push a frame onto the stack leaving |
| + // the frame pointer in the caller. |
| + // |
| + // PC -> STUB |
| + // FP -> DART3 <-+ |
| + // DART2 <-| <- TOP FRAME RETURN ADDRESS. |
| + // DART1 <-| |
| + // ..... |
| + // |
| + // In this case, traversing the linked stack frames will not collect a PC |
| + // inside DART3. The stack will incorrectly be: STUB, DART2, DART1. |
| + // In Dart code, after pushing the FP onto the stack, an IP in the current |
| + // function is pushed onto the stack as well. This stack slot is called |
| + // the PC marker. We can use the PC marker to insert DART3 into the stack |
| + // so that it will correctly be: STUB, DART3, DART2, DART1. Note the |
| + // inserted PC may not accurately reflect the true return address from STUB. |
| + ASSERT(!code_.IsNull()); |
| + if (sample->sp() == sample->fp()) { |
| + // Haven't pushed pc marker yet. |
| + return; |
| + } |
| + uword pc_marker = sample->pc_marker(); |
| + if (code_.ContainsInstructionAt(pc_marker)) { |
| + // PC marker is in the same code as pc, no missing frame. |
| + return; |
| + } |
| + if (!ContainedInDartCodeHeaps(pc_marker)) { |
| + // Not a valid PC marker. |
| + return; |
| + } |
| + sample->InsertCallerForTopFrame(pc_marker); |
| + } |
| + |
| + bool ContainedInDartCodeHeaps(uword pc) { |
| + return isolate()->heap()->CodeContains(pc) || |
| + vm_isolate()->heap()->CodeContains(pc); |
| + } |
| + |
| + Isolate* vm_isolate() const { |
| + return vm_isolate_; |
| + } |
| + |
| + RawCode* FindCodeForPC(uword pc) { |
| + // Check current isolate for pc. |
| + if (isolate()->heap()->CodeContains(pc)) { |
| + return Code::LookupCode(pc); |
| + } |
| + // Check VM isolate for pc. |
| + if (vm_isolate()->heap()->CodeContains(pc)) { |
| + return Code::LookupCodeInVmIsolate(pc); |
| + } |
| + return Code::null(); |
| + } |
| + |
| + Code& code_; |
|
srdjan
2014/05/02 18:20:29
Code*. We try to use reference with const.
|
| + |
| + Isolate* vm_isolate_; |
| +}; |
| + |
| + |
| class CodeRegionTableBuilder : public SampleVisitor { |
| public: |
| CodeRegionTableBuilder(Isolate* isolate, |
| @@ -1356,6 +1445,12 @@ void Profiler::PrintJSON(Isolate* isolate, JSONStream* stream, |
| &dead_code_table, |
| &tag_code_table); |
| { |
| + // Preprocess samples and fix the caller when the top PC is in a |
| + // stub or intrinsic without a frame. |
| + FixTopFrameVisitor fixTopFrame(isolate); |
| + sample_buffer->VisitSamplesByReference(&fixTopFrame); |
| + } |
| + { |
| // Build CodeRegion tables. |
| ScopeStopwatch sw("CodeRegionTableBuilder"); |
| sample_buffer->VisitSamples(&builder); |
| @@ -1600,6 +1695,8 @@ class ProfilerNativeStackWalker : public ValueObject { |
| // the isolates stack limit. |
| lower_bound_ = original_sp_; |
| } |
| + // Store the PC marker for the top frame. |
| + sample_->set_pc_marker(GetCurrentFramePcMarker(fp)); |
| int i = 0; |
| for (; i < FLAG_profile_depth; i++) { |
| if (FLAG_profile_verify_stack_walk) { |
| @@ -1662,6 +1759,13 @@ class ProfilerNativeStackWalker : public ValueObject { |
| return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp)); |
| } |
| + uword GetCurrentFramePcMarker(uword* fp) { |
| + if (!ValidFramePointer(fp)) { |
| + return 0; |
| + } |
| + return *(fp + kPcMarkerSlotFromFp); |
| + } |
| + |
| bool ValidFramePointer(uword* fp) const { |
| if (fp == NULL) { |
| return false; |
| @@ -1672,7 +1776,6 @@ class ProfilerNativeStackWalker : public ValueObject { |
| return r; |
| } |
| - |
| Sample* sample_; |
| const uword stack_upper_; |
| const uword original_pc_; |
| @@ -1705,6 +1808,8 @@ void Profiler::RecordSampleInterruptCallback( |
| sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); |
| sample->set_vm_tag(isolate->vm_tag()); |
| sample->set_user_tag(isolate->user_tag()); |
| + sample->set_sp(state.sp); |
| + sample->set_fp(state.fp); |
| if (FLAG_profile_native_stack) { |
| // Collect native and Dart frames. |
| uword stack_lower = 0; |