[gjs/mem-track: 2/5] gjs: dump heaps on signal
- From: Johan Bilien <jobi src gnome org>
- To: svn-commits-list gnome org
- Subject: [gjs/mem-track: 2/5] gjs: dump heaps on signal
- Date: Mon, 8 Jun 2009 13:28:47 -0400 (EDT)
commit 6beed5b007fe1650a570fd30c26b8f60f8c20af8
Author: Tommi Komulainen <tko litl com>
Date: Mon Jan 26 14:05:23 2009 +0000
gjs: dump heaps on signal
When GJS_DEBUG_HEAP_OUTPUT environment variable is set, set up SIGUSR1 signal
handler to dump JS heaps (using JS_DumpHeap) to file to aid debugging memory
leaks.
The log files generated will be ${GJS_DEBUG_HEAP_OUTPUT}.${pid}.${counter}
Usage:
$ GJS_DEBUG_HEAP_OUTPUT=/tmp/gjs-heap gjs-console ...
$ kill -USR1 `pidof gjs-console`
$ less /tmp/gjs-heap.`pidof gjs-console`.0
NOTE: In order for this to work and JS_DumpHeap to be available
SpiderMonkey must have been compiled with --enable-debug.
However using the configure option also fails several assertions in
SpiderMonkey, most of them due to missing thread safety in GJS; when
SpiderMonkey is compiled with JS_THREADSAFE most (all?) calls are supposed
to be wrapped in JS_BeginRequest / JS_EndRequest which we're currently not
doing at all. The simplest way to ignore the issue is to edit jsutil.h and
forcefully disable assertions.
Also DEBUG must be defined before including <jsapi.h> for JS_DumpHeap to be
declared; none of the installed SpiderMonkey header or pkg-config files
defines it.
---
gjs/context.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 113 insertions(+), 0 deletions(-)
diff --git a/gjs/context.c b/gjs/context.c
index 89184c2..591a673 100644
--- a/gjs/context.c
+++ b/gjs/context.c
@@ -36,6 +36,27 @@
#include <jsapi.h>
+#ifdef DEBUG
+/* NOTE: In order for this to work and JS_DumpHeap to be available
+ * SpiderMonkey must have been compiled with --enable-debug.
+ *
+ * However using the configure option also fails several assertions in
+ * SpiderMonkey, most of them due to missing thread safety in GJS; when
+ * SpiderMonkey is compiled with JS_THREADSAFE most (all?) calls are supposed
+ * to be wrapped in JS_BeginRequest / JS_EndRequest which we're currently not
+ * doing at all. The simplest way to ignore the issue is to edit jsutil.h and
+ * forcefully disable assertions.
+ *
+ * Also DEBUG must be defined before including <jsapi.h> for JS_DumpHeap to be
+ * declared; none of the installed SpiderMonkey header or pkg-config files
+ * defines it.
+ */
+#include "mem.h"
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
static void gjs_context_dispose (GObject *object);
static void gjs_context_finalize (GObject *object);
static GObject* gjs_context_constructor (GType type,
@@ -93,6 +114,97 @@ static GStaticMutex contexts_lock = G_STATIC_MUTEX_INIT;
static GList *all_contexts = NULL;
+#ifdef DEBUG
+static char *dump_heap_output = NULL;
+static guint dump_heap_idle_id = 0;
+
+static void
+gjs_context_dump_heap(GjsContext *js_context, FILE *fp)
+{
+ JS_DumpHeap(js_context->context, fp,
+ NULL, 0, /* start thing and kind */
+ NULL, /* thing to find */
+ 0xffff, /* max depth */
+ NULL); /* thing to ignore */
+}
+
+static void
+gjs_context_dump_heaps(void)
+{
+ static guint counter = 0;
+ char *filename;
+ FILE *fp;
+ GSList *l;
+
+ gjs_memory_report("signal handler", FALSE);
+
+ /* dump to sequential files to allow easier comparisons */
+ filename = g_strdup_printf("%s.%u.%u",
+ dump_heap_output,
+ (guint)getpid(),
+ counter);
+ ++counter;
+
+ fp = fopen(filename, "w");
+ g_free(filename);
+
+ if (!fp)
+ return;
+
+ for (l = all_gjs_contexts; l != NULL; l = l->next) {
+ GjsContext *js_context = l->data;
+
+ gjs_context_dump_heap(js_context, fp);
+ }
+
+ fclose(fp);
+}
+
+static gboolean
+dump_heap_idle(gpointer user_data)
+{
+ dump_heap_idle_id = 0;
+
+ gjs_context_dump_heaps();
+
+ return FALSE;
+}
+
+static void
+dump_heap_signal_handler(int signum)
+{
+ if (dump_heap_idle_id == 0)
+ dump_heap_idle_id = g_idle_add_full(G_PRIORITY_HIGH_IDLE,
+ dump_heap_idle,
+ NULL, NULL);
+}
+#endif
+
+static void
+setup_dump_heap(void)
+{
+#ifdef DEBUG
+ static gboolean dump_heap_initialized = FALSE;
+ if (!dump_heap_initialized) {
+ const char *heap_output;
+
+ dump_heap_initialized = TRUE;
+
+ /* install signal handler only if environment variable is set */
+ heap_output = g_getenv("GJS_DEBUG_HEAP_OUTPUT");
+ if (heap_output != NULL) {
+ struct sigaction sa;
+
+ dump_heap_output = g_strdup(heap_output);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = dump_heap_signal_handler;
+ sigaction(SIGUSR1, &sa, NULL);
+ }
+ }
+#endif
+}
+
static JSBool
gjs_log(JSContext *context,
JSObject *obj,
@@ -551,6 +663,7 @@ gjs_context_constructor (GType type,
g_static_mutex_unlock (&contexts_lock);
all_gjs_contexts = g_slist_prepend(all_gjs_contexts, js_context);
+ setup_dump_heap();
return object;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]