diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2020-01-08 19:42:39 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2020-01-08 19:42:39 +0000 |
commit | 39f48ff919a0ffae178511b4d585e6776a92733c (patch) | |
tree | 115c5ebf4a6b2f0c127bf1305aba924b206ed956 | |
parent | ece14c8410785b6d1f37a221307b1a0f1ca4e82d (diff) | |
download | mongo-39f48ff919a0ffae178511b4d585e6776a92733c.tar.gz |
SERVER-45357 use stacktrace API for HeapProfiler
-rw-r--r-- | src/mongo/util/heap_profiler.cpp | 88 | ||||
-rw-r--r-- | src/mongo/util/tcmalloc_parameters.idl | 4 |
2 files changed, 63 insertions, 29 deletions
diff --git a/src/mongo/util/heap_profiler.cpp b/src/mongo/util/heap_profiler.cpp index 2784eac8cfc..5229fd55620 100644 --- a/src/mongo/util/heap_profiler.cpp +++ b/src/mongo/util/heap_profiler.cpp @@ -31,6 +31,9 @@ #include "mongo/platform/basic.h" +#include <algorithm> +#include <memory> + #include "mongo/base/init.h" #include "mongo/base/static_assert.h" #include "mongo/config.h" @@ -127,6 +130,30 @@ namespace mongo { namespace { +// Simple wrapper for the demangler, particularly its buffer space. +class Demangler { +public: + Demangler() = default; + + Demangler(const Demangler&) = delete; + + ~Demangler() { + free(_buf); + } + + char* operator()(const char* sym) { + char* dm = abi::__cxa_demangle(sym, _buf, &_bufSize, &_status); + if (dm) + _buf = dm; + return dm; + } + +private: + size_t _bufSize = 0; + char* _buf = nullptr; + int _status = 0; +}; + // // Simple hash table maps Key->Value. // All storage is pre-allocated at creation. @@ -301,11 +328,11 @@ private: static const int kMaxStackInfos = 20000; // max number of unique call sites we handle static const int kStackHashTableLoadFactor = 2; // keep loading <50% - static const int kMaxFramesPerStack = 100; // max depth of stack + static const size_t kMaxFramesPerStack = 100; // max depth of stack // stack HashTable Key struct Stack { - int numFrames = 0; + size_t numFrames = 0; std::array<FrameInfo, kMaxFramesPerStack> frames; Stack() {} @@ -336,8 +363,8 @@ private: HashTable<Stack, StackInfo> stackHashTable{kMaxStackInfos, kStackHashTableLoadFactor}; // frames to skip at top and bottom of backtrace when reporting stacks - int skipStartFrames = 0; - int skipEndFrames = 0; + size_t skipStartFrames = 0; + size_t skipEndFrames = 0; // @@ -406,7 +433,7 @@ private: // Get backtrace. Stack tempStack; - tempStack.numFrames = backtrace(tempStack.frames.data(), kMaxFramesPerStack); + tempStack.numFrames = rawBacktrace(tempStack.frames.data(), kMaxFramesPerStack); // Compute backtrace hash. Hash stackHash = tempStack.hash(); @@ -472,38 +499,42 @@ private: // // Generate bson representation of stack. // - void generateStackIfNeeded(Stack& stack, StackInfo& stackInfo) { + void generateStackIfNeeded(StackTraceAddressMetadataGenerator& metaGen, + Demangler& demangler, + Stack& stack, + StackInfo& stackInfo) { if (!stackInfo.stackObj.isEmpty()) return; BSONArrayBuilder builder; - for (int j = skipStartFrames; j < stack.numFrames - skipEndFrames; j++) { - Dl_info dli; - StringData frameString; - char* demangled = nullptr; - if (dladdr(stack.frames[j], &dli)) { - if (dli.dli_sname) { - int status; - demangled = abi::__cxa_demangle(dli.dli_sname, nullptr, nullptr, &status); - if (demangled) { - // strip off function parameters as they are very verbose and not useful - char* p = strchr(demangled, '('); - if (p) - frameString = StringData(demangled, p - demangled); - else - frameString = demangled; - } else { - frameString = dli.dli_sname; + + std::string frameString; + + size_t jb = std::min(stack.numFrames, skipStartFrames); + size_t je = stack.numFrames - std::min(stack.numFrames - jb, skipEndFrames); + for (size_t j = jb; j != je; ++j) { + frameString.clear(); + void* addr = stack.frames[j]; + const auto& meta = metaGen.load(addr); + if (meta.symbol()) { + if (StringData name = meta.symbol().name(); !name.empty()) { + // Upgrade frameString to symbol name. + frameString.assign(name.begin(), name.end()); + if (char* dm = demangler(frameString.c_str())) { + // Further upgrade frameString to demangled name. + // We strip function parameters as they are very verbose and not useful. + frameString = dm; + if (auto paren = frameString.find('('); paren != std::string::npos) + frameString.erase(paren); } } } if (frameString.empty()) { + // Fall back to frameString as stringified `void*`. std::ostringstream s; - s << stack.frames[j]; + s << addr; frameString = s.str(); } builder.append(frameString); - if (demangled) - free(demangled); } stackInfo.stackObj = builder.obj(); log() << "heapProfile stack" << stackInfo.stackNum << ": " << stackInfo.stackObj; @@ -560,9 +591,12 @@ private: // We use stackinfo_mutex to ensure safety wrt concurrent updates to the StackInfo objects. // We can get skew between entries, which is ok. std::vector<StackInfo*> stackInfos; + + StackTraceAddressMetadataGenerator metaGen; + Demangler demangler; stackHashTable.forEach([&](Stack& stack, StackInfo& stackInfo) { if (stackInfo.activeBytes) { - generateStackIfNeeded(stack, stackInfo); + generateStackIfNeeded(metaGen, demangler, stack, stackInfo); stackInfos.push_back(&stackInfo); } }); diff --git a/src/mongo/util/tcmalloc_parameters.idl b/src/mongo/util/tcmalloc_parameters.idl index e9c9ffcc2a8..15993865720 100644 --- a/src/mongo/util/tcmalloc_parameters.idl +++ b/src/mongo/util/tcmalloc_parameters.idl @@ -54,7 +54,7 @@ server_parameters: cpp_varname: HeapProfilingEnabled default: false condition: - preprocessor: defined(_POSIX_VERSION) && defined(MONGO_CONFIG_HAVE_EXECINFO_BACKTRACE) + preprocessor: defined(_POSIX_VERSION) && (defined(MONGO_CONFIG_HAVE_EXECINFO_BACKTRACE) || defined(MONGO_USE_LIBUNWIND)) heapProfilingSampleIntervalBytes: description: "Configure heap profiling sample interval bytes" @@ -64,7 +64,7 @@ server_parameters: # 256kb default: 262144 condition: - preprocessor: defined(_POSIX_VERSION) && defined(MONGO_CONFIG_HAVE_EXECINFO_BACKTRACE) + preprocessor: defined(_POSIX_VERSION) && (defined(MONGO_CONFIG_HAVE_EXECINFO_BACKTRACE) || defined(MONGO_USE_LIBUNWIND)) tcmallocEnableMarkThreadTemporarilyIdle: description: 'REMOVED: Setting this parameter has no effect and it will be removed in a future version of MongoDB.' |