Browse Source

changed profiler from glib to own implementation that doesn't leak all the memory...

personal/stbuehler/wip
Thomas Porzelt 14 years ago
parent
commit
eb73fe1651
  1. 7
      src/lighttpd.c
  2. 4
      src/plugin_core.c
  3. 231
      src/profiler.c
  4. 22
      src/profiler.h
  5. 1
      src/wscript

7
src/lighttpd.c

@ -1,6 +1,7 @@
#include "base.h"
#include "config_parser.h"
#include "profiler.h"
#ifdef HAVE_LUA_H
#include "config_lua.h"
@ -33,7 +34,8 @@ int main(int argc, char *argv[]) {
/* check for environment variable LIGHTY_PROFILE_MEM */
gchar *profile_mem = getenv("LIGHTY_PROFILE_MEM");
if (profile_mem != NULL && g_str_equal(profile_mem, "true")) {
g_mem_set_vtable(glib_mem_profiler_table);
/*g_mem_set_vtable(glib_mem_profiler_table);*/
profiler_enable();
}
/* parse commandline options */
@ -132,5 +134,8 @@ int main(int argc, char *argv[]) {
if (free_config_path)
g_free(config_path);
if (profile_mem)
profiler_dump();
return 0;
}

4
src/plugin_core.c

@ -2,6 +2,7 @@
#include "base.h"
#include "plugin_core.h"
#include "utils.h"
#include "profiler.h"
@ -287,7 +288,8 @@ static action_result core_handle_profile_mem(connection *con, gpointer param) {
UNUSED(con);
UNUSED(param);
g_mem_profile();
/*g_mem_profile();*/
profiler_dump();
return ACTION_GO_ON;
}

231
src/profiler.c

@ -0,0 +1,231 @@
/* lighty memory profiler
* counts how many times malloc/realloc/free have been called and the amounts of bytes allocated/freed
* TODO: move hashtable to utils.c, optimize hashtable? implementation is very basic
*/
#include "base.h"
#include "profiler.h"
#define PROFILER_HASHTABLE_SIZE 1024
static profiler_mem stats_mem = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static GStaticMutex profiler_mutex = G_STATIC_MUTEX_INIT;
static gboolean profiler_enabled = FALSE;
struct profiler_entry {
gpointer addr;
gsize len;
struct profiler_entry *next;
};
typedef struct profiler_entry profiler_entry;
static struct {
profiler_entry **nodes;
} profiler_hashtable;
static void profiler_hashtable_init() {
profiler_hashtable.nodes = calloc(1, sizeof(profiler_entry*) * PROFILER_HASHTABLE_SIZE);
}
static profiler_entry *profiler_hashtable_find(gpointer addr) {
guint h = (gsize)addr % PROFILER_HASHTABLE_SIZE;
for (profiler_entry *e = profiler_hashtable.nodes[h]; e != NULL; e = e->next) {
if (e->addr == addr)
return e;
}
assert(NULL);
return NULL;
}
static void profiler_hashtable_insert(gpointer addr, gsize len) {
profiler_entry *e = malloc(sizeof(profiler_entry));
e->addr = addr;
e->len = len;
e->next = NULL;
guint h = (gsize)addr % PROFILER_HASHTABLE_SIZE;
if (profiler_hashtable.nodes[h] == NULL) {
profiler_hashtable.nodes[h] = e;
return;
}
for (profiler_entry *ec = profiler_hashtable.nodes[h];; ec = ec->next) {
if (ec->next == NULL) {
ec->next = e;
return;
}
}
}
static void profiler_hashtable_remove(gpointer addr) {
guint h = (gsize)addr % PROFILER_HASHTABLE_SIZE;
profiler_entry *prev = profiler_hashtable.nodes[h];
if (!prev)
return;
if (prev->addr == addr) {
if (prev->next)
profiler_hashtable.nodes[h] = prev->next;
else
profiler_hashtable.nodes[h] = NULL;
free(prev);
return;
}
for (profiler_entry *e = prev->next; e != NULL; e = e->next) {
if (e->addr == addr) {
prev->next = e->next;
free(e);
return;
}
prev = e;
}
}
static gpointer profiler_try_malloc(gsize n_bytes) {
/* we alloc sizeof(gsize) bytes more to hold n_bytes */
gsize *p;
p = malloc(n_bytes);
if (p) {
g_static_mutex_lock(&profiler_mutex);
profiler_hashtable_insert(p, n_bytes);
stats_mem.alloc_times++;
stats_mem.alloc_bytes += n_bytes;
stats_mem.inuse_bytes += n_bytes;
g_static_mutex_unlock(&profiler_mutex);
}
return p;
}
static gpointer profiler_malloc(gsize n_bytes) {
gpointer p = profiler_try_malloc(n_bytes);
assert(p);
return p;
}
static gpointer profiler_try_realloc(gpointer mem, gsize n_bytes) {
gsize l;
gsize *p = mem;
if (!mem) {
p = malloc(n_bytes);
g_static_mutex_lock(&profiler_mutex);
stats_mem.alloc_times++;
g_static_mutex_unlock(&profiler_mutex);
l = 0;
}
else {
p = realloc(p, n_bytes);
g_static_mutex_lock(&profiler_mutex);
profiler_entry *e = profiler_hashtable_find(mem);
l = e->len;
profiler_hashtable_remove(mem);
g_static_mutex_unlock(&profiler_mutex);
}
if (p) {
g_static_mutex_lock(&profiler_mutex);
profiler_hashtable_insert(p, n_bytes);
stats_mem.realloc_times++;
stats_mem.realloc_bytes += n_bytes;
stats_mem.inuse_bytes += n_bytes - l;
g_static_mutex_unlock(&profiler_mutex);
}
return p;
}
static gpointer profiler_realloc(gpointer mem, gsize n_bytes) {
gpointer p = profiler_try_realloc(mem, n_bytes);
assert(p);
return p;
}
static gpointer profiler_calloc(gsize n_blocks, gsize n_bytes) {
/* we alloc sizeof(gsize) bytes more to hold n_blocks*n_bytes */
gsize *p;
gsize l = n_blocks * n_bytes;
p = calloc(1, l);
if (p) {
g_static_mutex_lock(&profiler_mutex);
profiler_hashtable_insert(p, l);
stats_mem.calloc_times++;
stats_mem.calloc_bytes += l;
stats_mem.inuse_bytes += l;
g_static_mutex_unlock(&profiler_mutex);
}
assert(p);
return p;
}
static void profiler_free(gpointer mem) {
gsize *p = mem;
assert(p);
profiler_entry *e = profiler_hashtable_find(mem);
g_static_mutex_lock(&profiler_mutex);
stats_mem.free_times++;
stats_mem.free_bytes += e->len;
stats_mem.inuse_bytes -= e->len;
g_static_mutex_unlock(&profiler_mutex);
free(p);
profiler_hashtable_remove(mem);
}
/* public functions */
void profiler_enable() {
GMemVTable t;
if (profiler_enabled)
return;
profiler_enabled = TRUE;
profiler_hashtable_init();
t.malloc = profiler_malloc;
t.realloc = profiler_realloc;
t.free = profiler_free;
t.calloc = profiler_calloc;
t.try_malloc = profiler_try_malloc;
t.try_realloc = profiler_try_realloc;
g_mem_set_vtable(&t);
}
void profiler_dump() {
if (!profiler_enabled)
return;
g_static_mutex_lock(&profiler_mutex);
profiler_mem s = stats_mem;
g_static_mutex_unlock(&profiler_mutex);
g_print("--- memory profiler stats ---\n");
g_print("malloc(): called %" G_GUINT64_FORMAT " times, %" G_GUINT64_FORMAT " bytes total\n", s.alloc_times, s.alloc_bytes);
g_print("calloc(): called %" G_GUINT64_FORMAT " times, %" G_GUINT64_FORMAT " bytes total\n", s.calloc_times, s.calloc_bytes);
g_print("realloc(): called %" G_GUINT64_FORMAT " times, %" G_GUINT64_FORMAT " bytes total\n", s.realloc_times, s.realloc_bytes);
g_print("free(): called %" G_GUINT64_FORMAT " times, %" G_GUINT64_FORMAT " bytes total\n", s.free_times, s.free_bytes);
g_print("memory remaining: %" G_GUINT64_FORMAT " bytes, %" G_GUINT64_FORMAT " calls to free()\n", s.inuse_bytes, s.alloc_times + s.calloc_times - s.free_times);
}

22
src/profiler.h

@ -0,0 +1,22 @@
#ifndef _LIGHTTPD_PROFILER_H_
#define _LIGHTTPD_PROFILER_H_
struct profiler_mem;
typedef struct profiler_mem profiler_mem;
struct profiler_mem {
guint64 inuse_bytes;
guint64 alloc_times;
guint64 alloc_bytes;
guint64 calloc_times;
guint64 calloc_bytes;
guint64 realloc_times;
guint64 realloc_bytes;
guint64 free_times;
guint64 free_bytes;
};
void profiler_enable(); /* enables the profiler */
void profiler_dump(); /* dumps memory statistics to stdout */
#endif

1
src/wscript

@ -25,6 +25,7 @@ common_source='''
network_linux_sendfile.c
options.c
plugin.c
profiler.c
request.c
response.c
server.c

Loading…
Cancel
Save