summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2020-01-08 19:42:39 +0000
committerevergreen <evergreen@mongodb.com>2020-01-08 19:42:39 +0000
commit39f48ff919a0ffae178511b4d585e6776a92733c (patch)
tree115c5ebf4a6b2f0c127bf1305aba924b206ed956
parentece14c8410785b6d1f37a221307b1a0f1ca4e82d (diff)
downloadmongo-39f48ff919a0ffae178511b4d585e6776a92733c.tar.gz
SERVER-45357 use stacktrace API for HeapProfiler
-rw-r--r--src/mongo/util/heap_profiler.cpp88
-rw-r--r--src/mongo/util/tcmalloc_parameters.idl4
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.'