Added a leak detective method to report current memory usage with backtraces
This commit is contained in:
@@ -34,6 +34,7 @@
|
|||||||
#include <library.h>
|
#include <library.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <utils/backtrace.h>
|
#include <utils/backtrace.h>
|
||||||
|
#include <utils/hashtable.h>
|
||||||
|
|
||||||
typedef struct private_leak_detective_t private_leak_detective_t;
|
typedef struct private_leak_detective_t private_leak_detective_t;
|
||||||
|
|
||||||
@@ -310,6 +311,98 @@ static void uninstall_hooks()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hashtable hash function
|
||||||
|
*/
|
||||||
|
static u_int hash(backtrace_t *key)
|
||||||
|
{
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
void *addr;
|
||||||
|
u_int hash = 0;
|
||||||
|
|
||||||
|
enumerator = key->create_frame_enumerator(key);
|
||||||
|
while (enumerator->enumerate(enumerator, &addr))
|
||||||
|
{
|
||||||
|
hash = chunk_hash_inc(chunk_from_thing(addr), hash);
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hashtable equals function
|
||||||
|
*/
|
||||||
|
static bool equals(backtrace_t *a, backtrace_t *b)
|
||||||
|
{
|
||||||
|
return a->equals(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(leak_detective_t, usage, void,
|
||||||
|
private_leak_detective_t *this, FILE *out)
|
||||||
|
{
|
||||||
|
int oldpolicy, thresh;
|
||||||
|
pthread_t thread_id = pthread_self();
|
||||||
|
struct sched_param oldparams, params;
|
||||||
|
memory_header_t *hdr;
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
hashtable_t *entries;
|
||||||
|
struct {
|
||||||
|
/** associated backtrace */
|
||||||
|
backtrace_t *backtrace;
|
||||||
|
/** total size of all allocations */
|
||||||
|
size_t bytes;
|
||||||
|
/** number of allocations */
|
||||||
|
u_int count;
|
||||||
|
} *entry;
|
||||||
|
|
||||||
|
thresh = lib->settings->get_int(lib->settings,
|
||||||
|
"libstrongswan.leak_detective.usage_threshold", 10240);
|
||||||
|
|
||||||
|
pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
|
||||||
|
params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||||
|
pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms);
|
||||||
|
uninstall_hooks();
|
||||||
|
|
||||||
|
entries = hashtable_create((hashtable_hash_t)hash,
|
||||||
|
(hashtable_equals_t)equals, 1024);
|
||||||
|
|
||||||
|
for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
|
||||||
|
{
|
||||||
|
entry = entries->get(entries, hdr->backtrace);
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
entry->bytes += hdr->bytes;
|
||||||
|
entry->count++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
INIT(entry,
|
||||||
|
.backtrace = hdr->backtrace,
|
||||||
|
.bytes = hdr->bytes,
|
||||||
|
.count = 1,
|
||||||
|
);
|
||||||
|
entries->put(entries, hdr->backtrace, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator = entries->create_enumerator(entries);
|
||||||
|
while (enumerator->enumerate(enumerator, NULL, &entry))
|
||||||
|
{
|
||||||
|
if (entry->bytes >= thresh)
|
||||||
|
{
|
||||||
|
fprintf(out, "%d bytes total, %d allocations, %d bytes average:\n",
|
||||||
|
entry->bytes, entry->count, entry->bytes / entry->count);
|
||||||
|
entry->backtrace->log(entry->backtrace, out, TRUE);
|
||||||
|
}
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
entries->destroy(entries);
|
||||||
|
|
||||||
|
install_hooks();
|
||||||
|
pthread_setschedparam(thread_id, oldpolicy, &oldparams);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook function for malloc()
|
* Hook function for malloc()
|
||||||
*/
|
*/
|
||||||
@@ -510,6 +603,7 @@ leak_detective_t *leak_detective_create()
|
|||||||
INIT(this,
|
INIT(this,
|
||||||
.public = {
|
.public = {
|
||||||
.report = _report,
|
.report = _report,
|
||||||
|
.usage = _usage,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -42,6 +42,13 @@ struct leak_detective_t {
|
|||||||
*/
|
*/
|
||||||
void (*report)(leak_detective_t *this, bool detailed);
|
void (*report)(leak_detective_t *this, bool detailed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report current memory usage to out.
|
||||||
|
*
|
||||||
|
* @param out target to write usage report to
|
||||||
|
*/
|
||||||
|
void (*usage)(leak_detective_t *this, FILE *out);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy a leak_detective instance.
|
* Destroy a leak_detective instance.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user