[opt](stacktrace) Optimize stacktrace output #22467
This commit is contained in:
@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user