diff options
author | Chris Wilson <chris+github@qwirx.com> | 2013-02-13 00:27:54 +0000 |
---|---|---|
committer | Chris Wilson <chris+github@qwirx.com> | 2013-02-13 00:27:54 +0000 |
commit | 51d63d54c9ab3a0d53760e0e8a6a5ac57963dd36 (patch) | |
tree | 1f4eb179bb8c3c1f63d178e81b301399c7a29729 /lib | |
parent | 24edb39601fa14de8d8ba3308fd9ec5377c815b8 (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.h | 15 | ||||
-rw-r--r-- | lib/common/DebugMemLeakFinder.cpp | 114 | ||||
-rw-r--r-- | lib/common/MemLeakFinder.h | 2 |
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); |