Browse Source

Add mallocinfo mode to `getmemoryinfo` RPC

This adds a mode argument to `getmemoryinfo`. By default the output
will remain the same. However if a mode argument of `mallocinfo` is
provided the result of glibc `malloc_info` (if available) will
be returned as a string, as-is.

This is useful for tracking heap usage over time or troubleshooting
memory fragmentation issues.
0.15
Wladimir J. van der Laan 8 years ago
parent
commit
e141aa4ba6
  1. 7
      configure.ac
  2. 48
      src/rpc/misc.cpp

7
configure.ac

@ -566,6 +566,13 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],
[ AC_MSG_RESULT(no)] [ AC_MSG_RESULT(no)]
) )
dnl Check for malloc_info (for memory statistics information in getmemoryinfo)
AC_MSG_CHECKING(for getmemoryinfo)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]],
[[ int f = malloc_info(0, NULL); ]])],
[ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MALLOC_INFO, 1,[Define this symbol if you have malloc_info]) ],
[ AC_MSG_RESULT(no)]
)
AC_MSG_CHECKING([for visibility attribute]) AC_MSG_CHECKING([for visibility attribute])
AC_LINK_IFELSE([AC_LANG_SOURCE([ AC_LINK_IFELSE([AC_LANG_SOURCE([

48
src/rpc/misc.cpp

@ -20,6 +20,9 @@
#endif #endif
#include <stdint.h> #include <stdint.h>
#ifdef HAVE_MALLOC_INFO
#include <malloc.h>
#endif
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
@ -485,16 +488,39 @@ static UniValue RPCLockedMemoryInfo()
return obj; return obj;
} }
#ifdef HAVE_MALLOC_INFO
static std::string RPCMallocInfo()
{
char *ptr = nullptr;
size_t size = 0;
FILE *f = open_memstream(&ptr, &size);
if (f) {
malloc_info(0, f);
fclose(f);
if (ptr) {
std::string rv(ptr, size);
free(ptr);
return rv;
}
}
return "";
}
#endif
UniValue getmemoryinfo(const JSONRPCRequest& request) UniValue getmemoryinfo(const JSONRPCRequest& request)
{ {
/* Please, avoid using the word "pool" here in the RPC interface or help, /* Please, avoid using the word "pool" here in the RPC interface or help,
* as users will undoubtedly confuse it with the other "memory pool" * as users will undoubtedly confuse it with the other "memory pool"
*/ */
if (request.fHelp || request.params.size() != 0) if (request.fHelp || request.params.size() > 1)
throw std::runtime_error( throw std::runtime_error(
"getmemoryinfo\n" "getmemoryinfo (\"mode\")\n"
"Returns an object containing information about memory usage.\n" "Returns an object containing information about memory usage.\n"
"\nResult:\n" "Arguments:\n"
"1. \"mode\" determines what kind of information is returned. This argument is optional, the default mode is \"stats\".\n"
" - \"stats\" returns general statistics about memory usage in the daemon.\n"
" - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+).\n"
"\nResult (mode \"stats\"):\n"
"{\n" "{\n"
" \"locked\": { (json object) Information about locked memory manager\n" " \"locked\": { (json object) Information about locked memory manager\n"
" \"used\": xxxxx, (numeric) Number of bytes used\n" " \"used\": xxxxx, (numeric) Number of bytes used\n"
@ -505,13 +531,27 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
" \"chunks_free\": xxxxx, (numeric) Number unused chunks\n" " \"chunks_free\": xxxxx, (numeric) Number unused chunks\n"
" }\n" " }\n"
"}\n" "}\n"
"\nResult (mode \"mallocinfo\"):\n"
"\"<malloc version=\"1\">...\"\n"
"\nExamples:\n" "\nExamples:\n"
+ HelpExampleCli("getmemoryinfo", "") + HelpExampleCli("getmemoryinfo", "")
+ HelpExampleRpc("getmemoryinfo", "") + HelpExampleRpc("getmemoryinfo", "")
); );
std::string mode = (request.params.size() < 1 || request.params[0].isNull()) ? "stats" : request.params[0].get_str();
if (mode == "stats") {
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("locked", RPCLockedMemoryInfo())); obj.push_back(Pair("locked", RPCLockedMemoryInfo()));
return obj; return obj;
} else if (mode == "mallocinfo") {
#ifdef HAVE_MALLOC_INFO
return RPCMallocInfo();
#else
throw JSONRPCError(RPC_INVALID_PARAMETER, "mallocinfo is only available when compiled with glibc 2.10+");
#endif
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown mode " + mode);
}
} }
UniValue echo(const JSONRPCRequest& request) UniValue echo(const JSONRPCRequest& request)
@ -531,7 +571,7 @@ static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode { // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ---------- // --------------------- ------------------------ ----------------------- ----------
{ "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */ { "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */
{ "control", "getmemoryinfo", &getmemoryinfo, true, {} }, { "control", "getmemoryinfo", &getmemoryinfo, true, {"mode"} },
{ "util", "validateaddress", &validateaddress, true, {"address"} }, /* uses wallet if enabled */ { "util", "validateaddress", &validateaddress, true, {"address"} }, /* uses wallet if enabled */
{ "util", "createmultisig", &createmultisig, true, {"nrequired","keys"} }, { "util", "createmultisig", &createmultisig, true, {"nrequired","keys"} },
{ "util", "verifymessage", &verifymessage, true, {"address","signature","message"} }, { "util", "verifymessage", &verifymessage, true, {"address","signature","message"} },

Loading…
Cancel
Save