summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorChris Wilson <chris+github@qwirx.com>2013-02-13 00:27:54 +0000
committerChris Wilson <chris+github@qwirx.com>2013-02-13 00:27:54 +0000
commit51d63d54c9ab3a0d53760e0e8a6a5ac57963dd36 (patch)
tree1f4eb179bb8c3c1f63d178e81b301399c7a29729 /lib
parent24edb39601fa14de8d8ba3308fd9ec5377c815b8 (diff)
Add ability to generate memory usage reports while running.
* ./configure CXXFLAGS=-DDEBUG_LEAKS * Build and run the binary as normal (release or debug) * Send SIGUSR1 to the process (e.g. killall -USR1 bbstored) * Check the system logs, or the console. Not safe for use on a production process, as it does illegal things in a signal handler that may result in the process hanging. Use only for debugging, and be prepared to kill any stuck processes.
Diffstat (limited to 'lib')
-rw-r--r--lib/common/Box.h15
-rw-r--r--lib/common/DebugMemLeakFinder.cpp114
-rw-r--r--lib/common/MemLeakFinder.h2
3 files changed, 122 insertions, 9 deletions
diff --git a/lib/common/Box.h b/lib/common/Box.h
index bbff2ccb..316f4364 100644
--- a/lib/common/Box.h
+++ b/lib/common/Box.h
@@ -40,7 +40,6 @@
#include "Logging.h"
#ifndef BOX_RELEASE_BUILD
-
extern bool AssertFailuresToSyslog;
#define ASSERT_FAILS_TO_SYSLOG_ON {AssertFailuresToSyslog = true;}
void BoxDebugAssertFailed(const char *cond, const char *file, int line);
@@ -71,7 +70,6 @@
// Exception names
#define EXCEPTION_CODENAMES_EXTENDED
-
#else
#define ASSERT_FAILS_TO_SYSLOG_ON
#define ASSERT(cond)
@@ -82,9 +80,20 @@
// Box Backup builds release get extra information for exception logging
#define EXCEPTION_CODENAMES_EXTENDED
#define EXCEPTION_CODENAMES_EXTENDED_WITH_DESCRIPTION
-
#endif
+#if defined DEBUG_LEAKS
+ #ifdef PLATFORM_DISABLE_MEM_LEAK_TESTING
+ #error Compiling with DEBUG_LEAKS enabled, but not supported on this platform
+ #else
+ #define BOX_MEMORY_LEAK_TESTING
+ #endif
+#elif defined BOX_RELEASE_BUILD
+ #ifndef PLATFORM_DISABLE_MEM_LEAK_TESTING
+ #define BOX_MEMORY_LEAK_TESTING
+ #endif
+#endif // DEBUG_LEAKS || BOX_RELEASE_BUILD
+
#ifdef BOX_MEMORY_LEAK_TESTING
// Memory leak testing
#include "MemLeakFinder.h"
diff --git a/lib/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp
index 72891cd1..a4f8d41e 100644
--- a/lib/common/DebugMemLeakFinder.cpp
+++ b/lib/common/DebugMemLeakFinder.cpp
@@ -7,11 +7,10 @@
//
// --------------------------------------------------------------------------
-
-#ifndef BOX_RELEASE_BUILD
-
#include "Box.h"
+#ifdef BOX_MEMORY_LEAK_TESTING
+
#undef malloc
#undef realloc
#undef free
@@ -20,11 +19,13 @@
#include <unistd.h>
#endif
-#include <map>
+#include <signal.h>
#include <stdio.h>
#include <string.h>
-#include <set>
+
#include <cstdlib> // for std::atexit
+#include <map>
+#include <set>
#include "MemLeakFinder.h"
@@ -73,6 +74,13 @@ namespace
size_t sNotLeaksPreNum = 0;
}
+void memleakfinder_report_on_signal(int unused)
+{
+ // this is not safe! do not send SIGUSR1 to a process
+ // in a production environment!
+ memleakfinder_report_usage_summary();
+}
+
void memleakfinder_init()
{
ASSERT(!memleakfinder_initialised);
@@ -84,6 +92,21 @@ void memleakfinder_init()
}
memleakfinder_initialised = true;
+
+ #if defined WIN32
+ // no signals, no way to trigger event yet
+ #else
+ struct sigaction newact, oldact;
+ newact.sa_handler = memleakfinder_report_on_signal;
+ newact.sa_flags = SA_RESTART;
+ sigemptyset(&newact.sa_mask);
+ if (::sigaction(SIGUSR1, &newact, &oldact) != 0)
+ {
+ BOX_ERROR("Failed to install USR1 signal handler");
+ THROW_EXCEPTION(CommonException, Internal);
+ }
+ ASSERT(oldact.sa_handler == 0);
+ #endif // WIN32
}
MemLeakSuppressionGuard::MemLeakSuppressionGuard()
@@ -346,6 +369,85 @@ int memleakfinder_numleaks()
return n;
}
+// Summarise all blocks allocated and still allocated, for memory usage
+// diagnostics.
+void memleakfinder_report_usage_summary()
+{
+ InternalAllocGuard guard;
+
+ ASSERT(!sTrackingDataDestroyed);
+
+ typedef std::map<std::string, std::pair<uint64_t, uint64_t> > usage_map_t;
+ usage_map_t usage;
+
+ for(std::map<void *, MallocBlockInfo>::const_iterator
+ i(sMallocBlocks.begin()); i != sMallocBlocks.end(); ++i)
+ {
+ std::ostringstream buf;
+ buf << i->second.file << ":" << i->second.line;
+ std::string key = buf.str();
+
+ usage_map_t::iterator ui = usage.find(key);
+ if(ui == usage.end())
+ {
+ usage[key] = std::pair<uint64_t, uint64_t>(1,
+ i->second.size);
+ }
+ else
+ {
+ ui->second.first++;
+ ui->second.second += i->second.size;
+ }
+ }
+
+ for(std::map<void *, ObjectInfo>::const_iterator
+ i(sObjectBlocks.begin()); i != sObjectBlocks.end(); ++i)
+ {
+ std::ostringstream buf;
+ buf << i->second.file << ":" << i->second.line;
+ std::string key = buf.str();
+
+ usage_map_t::iterator ui = usage.find(key);
+ if(ui == usage.end())
+ {
+ usage[key] = std::pair<uint64_t, uint64_t>(1,
+ i->second.size);
+ }
+ else
+ {
+ ui->second.first++;
+ ui->second.second += i->second.size;
+ }
+ }
+
+ #ifndef DEBUG_LEAKS
+ BOX_WARNING("Memory use: support not compiled in :(");
+ #else
+ if(usage.empty())
+ {
+ BOX_WARNING("Memory use: none detected?!");
+ }
+ else
+ {
+ uint64_t blocks = 0, bytes = 0;
+ BOX_WARNING("Memory use: report follows");
+
+ for(usage_map_t::iterator i = usage.begin(); i != usage.end();
+ i++)
+ {
+ BOX_WARNING("Memory use: " << i->first << ": " <<
+ i->second.first << " blocks, " <<
+ i->second.second << " bytes");
+ blocks += i->second.first;
+ bytes += i->second.second;
+ }
+
+ BOX_WARNING("Memory use: report ends, total: " << blocks <<
+ " blocks, " << bytes << " bytes");
+ }
+ #endif // DEBUG_LEAKS
+}
+
void memleakfinder_reportleaks_file(FILE *file)
{
InternalAllocGuard guard;
@@ -549,4 +651,4 @@ void operator delete(void *ptr) throw ()
internal_delete(ptr);
}
-#endif // BOX_RELEASE_BUILD
+#endif // BOX_MEMORY_LEAK_TESTING
diff --git a/lib/common/MemLeakFinder.h b/lib/common/MemLeakFinder.h
index ca207bd5..91c93217 100644
--- a/lib/common/MemLeakFinder.h
+++ b/lib/common/MemLeakFinder.h
@@ -36,6 +36,8 @@ void memleakfinder_init();
int memleakfinder_numleaks();
+void memleakfinder_report_usage_summary();
+
void memleakfinder_reportleaks();
void memleakfinder_reportleaks_appendfile(const char *filename, const char *markertext);