[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 {
const intptr_t kSkipCount = 5;
const intptr_t kSkipCount = 4;
} // namespace dart

View file

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

View file

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

View file

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

View file

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