[opt](stacktrace) Optimize stacktrace output #22467

This commit is contained in:
Xinyi Zou
2023-08-06 15:53:53 +08:00
committed by GitHub
parent d628baba0a
commit c2c01825c1
5 changed files with 61 additions and 33 deletions

View File

@ -34,11 +34,14 @@
#include <unordered_map>
#include "config.h"
#include "util/string_util.h"
#include "vec/common/demangle.h"
#include "vec/common/hex.h"
#if USE_UNWIND
#include <libunwind.h>
#else
#include <execinfo.h>
#endif
namespace {
@ -294,12 +297,14 @@ StackTrace::StackTrace(const ucontext_t& signal_context) {
}
void StackTrace::tryCapture() {
// When unw_backtrace is not available, fall back on the standard
// `backtrace` function from execinfo.h.
#if USE_UNWIND
size = unw_backtrace(frame_pointers.data(), capacity);
__msan_unpoison(frame_pointers.data(), size * sizeof(frame_pointers[0]));
#else
size = 0;
size = backtrace(frame_pointers.data(), capacity);
#endif
__msan_unpoison(frame_pointers.data(), size * sizeof(frame_pointers[0]));
}
/// ClickHouse uses bundled libc++ so type names will be the same on every system thus it's safe to hardcode them
@ -340,7 +345,7 @@ constexpr bool operator<(const MaybeRef auto& left, const MaybeRef auto& right)
std::tuple {right.pointers, right.size, right.offset};
}
static void toStringEveryLineImpl([[maybe_unused]] bool fatal,
static void toStringEveryLineImpl([[maybe_unused]] const std::string dwarf_location_info_mode,
const StackTraceRefTriple& stack_trace,
std::function<void(std::string_view)> callback) {
if (stack_trace.size == 0) {
@ -349,7 +354,20 @@ static void toStringEveryLineImpl([[maybe_unused]] bool fatal,
#if defined(__ELF__) && !defined(__FreeBSD__)
using enum doris::Dwarf::LocationInfoMode;
const auto mode = fatal ? FULL_WITH_INLINE : FAST;
doris::Dwarf::LocationInfoMode mode;
auto dwarf_location_info_mode_lower = doris::to_lower(dwarf_location_info_mode);
if (dwarf_location_info_mode_lower == "disabled") {
mode = DISABLED;
} else if (dwarf_location_info_mode_lower == "fast") {
mode = FAST;
} else if (dwarf_location_info_mode_lower == "full") {
mode = FULL;
} else if (dwarf_location_info_mode_lower == "full_with_inline") {
mode = FULL_WITH_INLINE;
} else {
LOG(INFO) << "invalid LocationInfoMode: " << dwarf_location_info_mode;
mode = DISABLED;
}
auto symbol_index_ptr = doris::SymbolIndex::instance();
const doris::SymbolIndex& symbol_index = *symbol_index_ptr;
std::unordered_map<std::string, doris::Dwarf> dwarfs;
@ -362,7 +380,21 @@ static void toStringEveryLineImpl([[maybe_unused]] bool fatal,
reinterpret_cast<const void*>(uintptr_t(virtual_addr) - virtual_offset);
std::stringstream out;
out << i << ". ";
out << "\t" << i << ". ";
if (i < 10) { // for alignment
out << " ";
}
if (shouldShowAddress(physical_addr)) {
out << "@ ";
writePointerHex(physical_addr, out);
}
if (const auto* const symbol = symbol_index.findSymbol(virtual_addr)) {
out << " " << collapseNames(demangle(symbol->name));
} else {
out << " ?";
}
if (std::error_code ec; object && std::filesystem::exists(object->name, ec) && !ec) {
auto dwarf_it = dwarfs.try_emplace(object->name, object->elf).first;
@ -371,31 +403,20 @@ static void toStringEveryLineImpl([[maybe_unused]] bool fatal,
if (dwarf_it->second.findAddress(uintptr_t(physical_addr), location, mode,
inline_frames)) {
out << location.file.toString() << ":" << location.line << ": ";
out << " " << location.file.toString() << ":" << location.line;
}
}
if (const auto* const symbol = symbol_index.findSymbol(virtual_addr)) {
out << collapseNames(demangle(symbol->name));
} else {
out << "?";
}
out << " in " << (object ? object->name : "?");
if (shouldShowAddress(physical_addr)) {
out << " @ ";
writePointerHex(physical_addr, out);
}
out << " in " << (object ? object->name : "?");
callback(out.str());
for (size_t j = 0; j < inline_frames.size(); ++j) {
const auto& frame = inline_frames[j];
callback(fmt::format("{}.{}. inlined from {}:{}: {}", i, j + 1,
frame.location.file.toString(), frame.location.line,
collapseNames(demangle(frame.name))));
callback(fmt::format("\t{}.{}. inlined from {}: {}:{}", i, j + 1,
collapseNames(demangle(frame.name)),
frame.location.file.toString(), frame.location.line));
}
callback(out.str());
}
#else
for (size_t i = stack_trace.offset; i < stack_trace.size; ++i)
@ -405,7 +426,7 @@ static void toStringEveryLineImpl([[maybe_unused]] bool fatal,
}
void StackTrace::toStringEveryLine(std::function<void(std::string_view)> callback) const {
toStringEveryLineImpl(true, {frame_pointers, offset, size}, std::move(callback));
toStringEveryLineImpl("FULL_WITH_INLINE", {frame_pointers, offset, size}, std::move(callback));
}
using StackTraceCache = std::map<StackTraceTriple, std::string, std::less<>>;
@ -430,14 +451,18 @@ std::string toStringCached(const StackTrace::FramePointers& pointers, size_t off
return it->second;
} else {
std::stringstream out;
toStringEveryLineImpl(false, key, [&](std::string_view str) { out << str << '\n'; });
toStringEveryLineImpl(doris::config::dwarf_location_info_mode, key,
[&](std::string_view str) { out << str << '\n'; });
return cache.emplace(StackTraceTriple {pointers, offset, size}, out.str()).first->second;
}
}
std::string StackTrace::toString() const {
return toStringCached(frame_pointers, offset, size);
// Delete the first three frame pointers, which are inside the stacktrace.
StackTrace::FramePointers frame_pointers_raw {};
std::copy(frame_pointers.begin() + 3, frame_pointers.end(), frame_pointers_raw.begin());
return toStringCached(frame_pointers_raw, offset, size - 3);
}
std::string StackTrace::toString(void** frame_pointers_raw, size_t offset, size_t size) {