Commit 3ba178b5 authored by Philip Pronin's avatar Philip Pronin Committed by Facebook Github Bot

reduce consumed stack size in symbolizer

Summary:
It currently takes ~32kB of stack trace to run symbolizer, which is
very close to ASan alt stack size (32 kB).

If we exclude `demangle` (which can use unbound stack size in extreme cases),
the heaviest path in symbolizer includes `FrameArray<100>` and three arrays of
`PATH_MAX` (4 kB) size.  This diff removes the former and one of the latters,
reducing this code path from 32 kB to ~10 kB.

Reviewed By: ot, yfeldblum

Differential Revision: D4618467

fbshipit-source-id: e6a53b61b3d5f6e8b892216d2e9b839ed8430d0e
parent ba35fe5d
...@@ -64,8 +64,8 @@ std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) { ...@@ -64,8 +64,8 @@ std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) {
return nullptr; return nullptr;
} }
Path path(p); scratchpad_.assign(p);
auto pos = map_.find(path); auto pos = map_.find(scratchpad_);
if (pos != map_.end()) { if (pos != map_.end()) {
return slots_[pos->second]; return slots_[pos->second];
} }
...@@ -79,12 +79,12 @@ std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) { ...@@ -79,12 +79,12 @@ std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) {
auto& f = slots_[n]; auto& f = slots_[n];
const char* msg = ""; const char* msg = "";
int r = f->openAndFollow(path.data(), true, &msg); int r = f->openAndFollow(scratchpad_.data(), true, &msg);
if (r != ElfFile::kSuccess) { if (r != ElfFile::kSuccess) {
return nullptr; return nullptr;
} }
map_[path] = n; map_[scratchpad_] = n;
return f; return f;
} }
......
...@@ -70,9 +70,19 @@ class SignalSafeElfCache : public ElfCacheBase { ...@@ -70,9 +70,19 @@ class SignalSafeElfCache : public ElfCacheBase {
// own wrapper around a fixed-size, null-terminated string. // own wrapper around a fixed-size, null-terminated string.
class Path : private boost::totally_ordered<Path> { class Path : private boost::totally_ordered<Path> {
public: public:
Path() {
assign(folly::StringPiece());
}
explicit Path(StringPiece s) { explicit Path(StringPiece s) {
assign(s);
}
void assign(StringPiece s) {
DCHECK_LE(s.size(), kMaxSize); DCHECK_LE(s.size(), kMaxSize);
memcpy(data_, s.data(), s.size()); if (!s.empty()) {
memcpy(data_, s.data(), s.size());
}
data_[s.size()] = '\0'; data_[s.size()] = '\0';
} }
...@@ -94,6 +104,7 @@ class SignalSafeElfCache : public ElfCacheBase { ...@@ -94,6 +104,7 @@ class SignalSafeElfCache : public ElfCacheBase {
char data_[kMaxSize + 1]; char data_[kMaxSize + 1];
}; };
Path scratchpad_; // Preallocated key for map_ lookups.
boost::container::flat_map<Path, int> map_; boost::container::flat_map<Path, int> map_;
std::vector<std::shared_ptr<ElfFile>> slots_; std::vector<std::shared_ptr<ElfFile>> slots_;
}; };
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <folly/Conv.h> #include <folly/Conv.h>
#include <folly/FileUtil.h> #include <folly/FileUtil.h>
#include <folly/Memory.h>
#include <folly/ScopeGuard.h> #include <folly/ScopeGuard.h>
#include <folly/String.h> #include <folly/String.h>
...@@ -383,8 +384,8 @@ StackTracePrinter::StackTracePrinter(size_t minSignalSafeElfCacheSize, int fd) ...@@ -383,8 +384,8 @@ StackTracePrinter::StackTracePrinter(size_t minSignalSafeElfCacheSize, int fd)
printer_( printer_(
fd, fd,
SymbolizePrinter::COLOR_IF_TTY, SymbolizePrinter::COLOR_IF_TTY,
size_t(64) << 10) // 64KiB size_t(64) << 10), // 64KiB
{} addresses_(make_unique<FrameArray<kMaxStackTraceDepth>>()) {}
void StackTracePrinter::flush() { void StackTracePrinter::flush() {
printer_.flush(); printer_.flush();
...@@ -395,33 +396,31 @@ void StackTracePrinter::printStackTrace(bool symbolize) { ...@@ -395,33 +396,31 @@ void StackTracePrinter::printStackTrace(bool symbolize) {
SCOPE_EXIT { SCOPE_EXIT {
flush(); flush();
}; };
// Get and symbolize stack trace
constexpr size_t kMaxStackTraceDepth = 100;
FrameArray<kMaxStackTraceDepth> addresses;
// Skip the getStackTrace frame // Skip the getStackTrace frame
if (!getStackTraceSafe(addresses)) { if (!getStackTraceSafe(*addresses_)) {
print("(error retrieving stack trace)\n"); print("(error retrieving stack trace)\n");
} else if (symbolize) { } else if (symbolize) {
// Do our best to populate location info, process is going to terminate, // Do our best to populate location info, process is going to terminate,
// so performance isn't critical. // so performance isn't critical.
Symbolizer symbolizer(&elfCache_, Dwarf::LocationInfoMode::FULL); Symbolizer symbolizer(&elfCache_, Dwarf::LocationInfoMode::FULL);
symbolizer.symbolize(addresses); symbolizer.symbolize(*addresses_);
// Skip the top 2 frames: // Skip the top 2 frames:
// getStackTraceSafe // getStackTraceSafe
// StackTracePrinter::printStackTrace (here) // StackTracePrinter::printStackTrace (here)
// //
// Leaving signalHandler on the stack for clarity, I think. // Leaving signalHandler on the stack for clarity, I think.
printer_.println(addresses, 2); printer_.println(*addresses_, 2);
} else { } else {
print("(safe mode, symbolizer not available)\n"); print("(safe mode, symbolizer not available)\n");
AddressFormatter formatter; AddressFormatter formatter;
for (size_t i = 0; i < addresses.frameCount; ++i) { for (size_t i = 0; i < addresses_->frameCount; ++i) {
print(formatter.format(addresses.addresses[i])); print(formatter.format(addresses_->addresses[i]));
print("\n"); print("\n");
} }
} }
} }
} // namespace symbolizer
} // namespace symbolizer
} // namespace folly } // namespace folly
...@@ -324,6 +324,7 @@ class StringSymbolizePrinter : public SymbolizePrinter { ...@@ -324,6 +324,7 @@ class StringSymbolizePrinter : public SymbolizePrinter {
class StackTracePrinter { class StackTracePrinter {
public: public:
static constexpr size_t kDefaultMinSignalSafeElfCacheSize = 500; static constexpr size_t kDefaultMinSignalSafeElfCacheSize = 500;
explicit StackTracePrinter( explicit StackTracePrinter(
size_t minSignalSafeElfCacheSize = kDefaultMinSignalSafeElfCacheSize, size_t minSignalSafeElfCacheSize = kDefaultMinSignalSafeElfCacheSize,
int fd = STDERR_FILENO); int fd = STDERR_FILENO);
...@@ -343,9 +344,12 @@ class StackTracePrinter { ...@@ -343,9 +344,12 @@ class StackTracePrinter {
void flush(); void flush();
private: private:
static constexpr size_t kMaxStackTraceDepth = 100;
int fd_; int fd_;
SignalSafeElfCache elfCache_; SignalSafeElfCache elfCache_;
FDSymbolizePrinter printer_; FDSymbolizePrinter printer_;
std::unique_ptr<FrameArray<kMaxStackTraceDepth>> addresses_;
}; };
} // namespace symbolizer } // namespace symbolizer
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment