[vm, profiler] Improve profiler stacks and VM backtraces.

- Fix duplication of top frame from the native stack walker
 - Include frame pointer, useful for debugging stack overflows
 - Print dso name and offset when no symbol is available at runtime to allow offline symbolification

Change-Id: I150d508e7c370c26ddd836b9dd50c2a465c19ebf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/98432
Reviewed-by: Zach Anderson <zra@google.com>
This commit is contained in:
Ryan Macnak 2019-04-02 22:45:24 +00:00
parent 335a854696
commit d77a6064a9
5 changed files with 33 additions and 19 deletions

View file

@ -10,7 +10,7 @@
namespace dart { namespace dart {
const intptr_t kSkipCount = 5; const intptr_t kSkipCount = 4;
} // namespace dart } // namespace dart

View file

@ -10,7 +10,7 @@
namespace dart { namespace dart {
const intptr_t kSkipCount = 5; const intptr_t kSkipCount = 4;
} // namespace dart } // namespace dart

View file

@ -11,9 +11,9 @@
namespace dart { namespace dart {
#if defined(DEBUG) #if defined(DEBUG)
const intptr_t kSkipCount = 6;
#elif !(defined(PRODUCT) || defined(DEBUG))
const intptr_t kSkipCount = 5; const intptr_t kSkipCount = 5;
#elif !(defined(PRODUCT) || defined(DEBUG))
const intptr_t kSkipCount = 4;
#endif #endif
} // namespace dart } // namespace dart

View file

@ -11,9 +11,9 @@
namespace dart { namespace dart {
#if defined(DEBUG) #if defined(DEBUG)
const intptr_t kSkipCount = 6;
#elif !(defined(PRODUCT) || defined(DEBUG))
const intptr_t kSkipCount = 5; const intptr_t kSkipCount = 5;
#elif !(defined(PRODUCT) || defined(DEBUG))
const intptr_t kSkipCount = 4;
#endif #endif
} // namespace dart } // namespace dart

View file

@ -417,6 +417,7 @@ void ClearProfileVisitor::VisitSample(Sample* sample) {
static void DumpStackFrame(intptr_t frame_index, static void DumpStackFrame(intptr_t frame_index,
uword pc, uword pc,
uword fp,
bool try_symbolize_dart_frames) { bool try_symbolize_dart_frames) {
Thread* thread = Thread::Current(); Thread* thread = Thread::Current();
if ((thread != NULL) && !thread->IsAtSafepoint() && if ((thread != NULL) && !thread->IsAtSafepoint() &&
@ -430,7 +431,8 @@ static void DumpStackFrame(intptr_t frame_index,
code = Code::LookupCode(pc); // In current isolate. code = Code::LookupCode(pc); // In current isolate.
} }
if (!code.IsNull()) { if (!code.IsNull()) {
OS::PrintErr(" [0x%" Pp "] %s\n", pc, code.QualifiedName()); OS::PrintErr(" pc 0x%" Pp " fp 0x%" Pp " %s\n", pc, fp,
code.QualifiedName());
return; return;
} }
} }
@ -438,12 +440,24 @@ static void DumpStackFrame(intptr_t frame_index,
uintptr_t start = 0; uintptr_t start = 0;
char* native_symbol_name = NativeSymbolResolver::LookupSymbolName(pc, &start); char* native_symbol_name = NativeSymbolResolver::LookupSymbolName(pc, &start);
if (native_symbol_name == NULL) { if (native_symbol_name != NULL) {
OS::PrintErr(" [0x%" Pp "] Unknown symbol\n", pc); OS::PrintErr(" pc 0x%" Pp " fp 0x%" Pp " %s\n", pc, fp,
} else { native_symbol_name);
OS::PrintErr(" [0x%" Pp "] %s\n", pc, native_symbol_name);
NativeSymbolResolver::FreeSymbolName(native_symbol_name); NativeSymbolResolver::FreeSymbolName(native_symbol_name);
return;
} }
char* dso_name;
uword dso_base;
if (NativeSymbolResolver::LookupSharedObject(pc, &dso_base, &dso_name)) {
uword dso_offset = pc - dso_base;
OS::PrintErr(" pc 0x%" Pp " fp 0x%" Pp " %s+0x%" Px "\n", pc, fp, dso_name,
dso_offset);
NativeSymbolResolver::FreeSymbolName(dso_name);
return;
}
OS::PrintErr(" pc 0x%" Pp " fp 0x%" Pp " Uknown symbol\n", pc, fp);
} }
class ProfilerStackWalker : public ValueObject { class ProfilerStackWalker : public ValueObject {
@ -469,14 +483,14 @@ class ProfilerStackWalker : public ValueObject {
} }
} }
bool Append(uword pc) { bool Append(uword pc, uword fp) {
if (frames_skipped_ < skip_count_) { if (frames_skipped_ < skip_count_) {
frames_skipped_++; frames_skipped_++;
return true; return true;
} }
if (sample_ == NULL) { if (sample_ == NULL) {
DumpStackFrame(frame_index_, pc, try_symbolize_dart_frames_); DumpStackFrame(frame_index_, pc, fp, try_symbolize_dart_frames_);
frame_index_++; frame_index_++;
total_frames_++; total_frames_++;
return true; return true;
@ -632,7 +646,7 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
in_interpreted_frame)); in_interpreted_frame));
} }
if (!Append(reinterpret_cast<uword>(pc_))) { if (!Append(reinterpret_cast<uword>(pc_), reinterpret_cast<uword>(fp_))) {
break; // Sample is full. break; // Sample is full.
} }
@ -725,7 +739,7 @@ class ProfilerNativeStackWalker : public ProfilerStackWalker {
void walk() { void walk() {
const uword kMaxStep = VirtualMemory::PageSize(); const uword kMaxStep = VirtualMemory::PageSize();
Append(original_pc_); Append(original_pc_, original_fp_);
uword* pc = reinterpret_cast<uword*>(original_pc_); uword* pc = reinterpret_cast<uword*>(original_pc_);
uword* fp = reinterpret_cast<uword*>(original_fp_); uword* fp = reinterpret_cast<uword*>(original_fp_);
@ -747,10 +761,6 @@ class ProfilerNativeStackWalker : public ProfilerStackWalker {
} }
while (true) { while (true) {
if (!Append(reinterpret_cast<uword>(pc))) {
return;
}
pc = CallerPC(fp); pc = CallerPC(fp);
previous_fp = fp; previous_fp = fp;
fp = CallerFP(fp); fp = CallerFP(fp);
@ -794,6 +804,10 @@ class ProfilerNativeStackWalker : public ProfilerStackWalker {
// Move the lower bound up. // Move the lower bound up.
lower_bound_ = reinterpret_cast<uword>(fp); lower_bound_ = reinterpret_cast<uword>(fp);
if (!Append(reinterpret_cast<uword>(pc), reinterpret_cast<uword>(fp))) {
return;
}
} }
} }