Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(238)

Unified Diff: runtime/vm/profiler.cc

Issue 264933006: Fix edge case where profiler would miss the caller of the top frame (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/profiler.h ('k') | runtime/vm/reusable_handles.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/profiler.cc
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index d8ec5da69b8c6796a9570be71e38a0e308e84d52..49df08a5cb5c2fdffcee93c37e676556b45c76f7 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -13,6 +13,7 @@
#include "vm/object.h"
#include "vm/os.h"
#include "vm/profiler.h"
+#include "vm/reusable_handles.h"
#include "vm/signal_handler.h"
#include "vm/simulator.h"
#include "vm/stack_frame.h"
@@ -910,6 +911,98 @@ class CodeRegionTable : public ValueObject {
};
+class FixTopFrameVisitor : public SampleVisitor {
+ public:
+ explicit FixTopFrameVisitor(Isolate* isolate)
+ : SampleVisitor(isolate),
+ vm_isolate_(Dart::vm_isolate()) {
+ }
+
+ void VisitSample(Sample* sample) {
+ if (sample->processed()) {
+ // Already processed.
+ return;
+ }
+ REUSABLE_CODE_HANDLESCOPE(isolate());
+ // Mark that we've processed this sample.
+ sample->set_processed(true);
+ // Lookup code object for leaf frame.
+ Code& code = reused_code_handle.Handle();
+ code = FindCodeForPC(sample->At(0));
+ sample->set_leaf_frame_is_dart(!code.IsNull());
+ if (sample->pc_marker() == 0) {
+ // No pc marker. Nothing to do.
+ return;
+ }
+ if (!code.IsNull() && (code.compile_timestamp() > sample->timestamp())) {
+ // Code compiled after sample. Ignore.
+ return;
+ }
+ if (sample->leaf_frame_is_dart()) {
+ CheckForMissingDartFrame(code, sample);
+ }
+ }
+
+ private:
+ void CheckForMissingDartFrame(const Code& code, Sample* sample) const {
+ // 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) const {
+ return isolate()->heap()->CodeContains(pc) ||
+ vm_isolate()->heap()->CodeContains(pc);
+ }
+
+ Isolate* vm_isolate() const {
+ return vm_isolate_;
+ }
+
+ RawCode* FindCodeForPC(uword pc) const {
+ // 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();
+ }
+
+ Isolate* vm_isolate_;
+};
+
+
class CodeRegionTableBuilder : public SampleVisitor {
public:
CodeRegionTableBuilder(Isolate* isolate,
@@ -1356,6 +1449,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->VisitSamples(&fixTopFrame);
+ }
+ {
// Build CodeRegion tables.
ScopeStopwatch sw("CodeRegionTableBuilder");
sample_buffer->VisitSamples(&builder);
@@ -1600,6 +1699,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 +1763,13 @@ class ProfilerNativeStackWalker : public ValueObject {
return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp));
}
+ uword GetCurrentFramePcMarker(uword* fp) const {
+ if (!ValidFramePointer(fp)) {
+ return 0;
+ }
+ return *(fp + kPcMarkerSlotFromFp);
+ }
+
bool ValidFramePointer(uword* fp) const {
if (fp == NULL) {
return false;
@@ -1672,7 +1780,6 @@ class ProfilerNativeStackWalker : public ValueObject {
return r;
}
-
Sample* sample_;
const uword stack_upper_;
const uword original_pc_;
@@ -1705,6 +1812,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;
« no previous file with comments | « runtime/vm/profiler.h ('k') | runtime/vm/reusable_handles.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698