Support for gobject tracking in memprof
- From: Ricardo Fernández Pascual <ric users sourceforge net>
- To: otaylor redhat com, kris gtk org
- Cc: gnome-hackers gnome org
- Subject: Support for gobject tracking in memprof
- Date: 06 Aug 2002 15:54:26 +0200
Hello,
I've been playing with memprof and added support for tracking
GObjects (creation, ref, unref...).
It keeps a list of all live gobjects of the program and tracks where
every ref and unref is done.
I have used it to find some leaks in galeon. I have tested it with
several other programs and it seems to work correctly (btw: every gnome
program leaves a lot of live GtkObjects when exiting, i guess this is
intentional...).
If people find this useful, I could clean the code and commit it to
cvs. The patch is a bit dirty and has some code duplication because i
didn't expect to get this working when I started it ;)
Ricardo.
--
Ricardo Fernández Pascual
ric users sourceforge net
Murcia. España.
? memprof.gobjects.diff
Index: main.c
===================================================================
RCS file: /cvs/gnome/memprof/main.c,v
retrieving revision 1.21
diff -u -r1.21 main.c
--- main.c 15 Jul 2002 23:39:00 -0000 1.21
+++ main.c 5 Aug 2002 17:14:10 -0000
@@ -49,6 +49,7 @@
MPProcess *process;
Profile *profile;
GSList *leaks;
+ GHashTable *objects;
GtkWidget *main_window;
GtkWidget *main_notebook;
@@ -56,6 +57,9 @@
GtkWidget *bytes_per_label;
GtkWidget *total_bytes_label;
+ GtkWidget *live_objects_label;
+ GtkWidget *max_live_objects_label;
+
GtkWidget *profile_func_clist;
GtkWidget *profile_caller_clist;
GtkWidget *profile_child_clist;
@@ -63,6 +67,10 @@
GtkWidget *leak_block_clist;
GtkWidget *leak_stack_clist;
+ GtkWidget *objects_clist;
+ GtkWidget *objects_history_clist;
+ GtkWidget *objects_stack_clist;
+
GtkWidget *usage_max_label;
GtkWidget *usage_canvas;
@@ -144,6 +152,14 @@
gtk_label_set_text (GTK_LABEL (pwin->n_allocations_label), tmp);
g_free (tmp);
+ tmp = g_strdup_printf ("%d", pwin->process->live_objects);
+ gtk_label_set_text (GTK_LABEL (pwin->live_objects_label), tmp);
+ g_free (tmp);
+
+ tmp = g_strdup_printf ("%d", pwin->process->max_live_objects);
+ gtk_label_set_text (GTK_LABEL (pwin->max_live_objects_label), tmp);
+ g_free (tmp);
+
if (pwin->process->n_allocations == 0)
tmp = g_strdup("-");
else
@@ -571,6 +587,211 @@
/************************************************************
+ * GUI for GObjects report
+ ************************************************************/
+
+static void
+objects_history_select_row (GtkWidget *widget,
+ gint row,
+ gint column,
+ GdkEvent *event,
+ ProcessWindow *pwin)
+{
+ ObjectHistoryItem *it = gtk_clist_get_row_data (GTK_CLIST (widget), row);
+ int i;
+
+ if (it == NULL)
+ return;
+
+ gtk_clist_clear (GTK_CLIST (pwin->objects_stack_clist));
+ for (i = 0; i < it->stack_size; i++) {
+ char *data[3];
+ char buf[32];
+ const char *filename;
+ char *functionname;
+ unsigned int line;
+
+ if (!process_find_line (pwin->process, it->stack[i],
+ &filename, &functionname, &line)) {
+ /* 0x3f == '?' -- suppress trigraph warnings */
+ functionname = g_strdup ("(\x3f\x3f\x3f)");
+ filename = "(\x3f\x3f\x3f)";
+ line = 0;
+ }
+
+ data[0] = functionname;
+
+ g_snprintf(buf, 32, "%d", line);
+ data[1] = buf;
+
+ data[2] = (char *)filename;
+
+ gtk_clist_append (GTK_CLIST (pwin->objects_stack_clist), data);
+ free (data[0]);
+ }
+
+}
+
+static void
+objects_select_row (GtkWidget *widget,
+ gint row,
+ gint column,
+ GdkEvent *event,
+ ProcessWindow *pwin)
+{
+ ObjectInfo *obj;
+ GtkCList *clist;
+ GSList *li;
+
+ obj = gtk_clist_get_row_data (GTK_CLIST (pwin->objects_clist), row);
+ clist = GTK_CLIST (pwin->objects_history_clist);
+ gtk_clist_clear (clist);
+
+ if (!obj) return;
+
+ for (li = obj->history; li; li = li->next)
+ {
+ ObjectHistoryItem *it = li->data;
+ char *data[2];
+ char buf[32];
+ gint nrow;
+
+ data[0] = it->type == OH_REF ? "ref" :
+ it->type == OH_UNREF ? "unref" :
+ "new";
+
+ g_snprintf(buf, 32, "%d", it->old_refcount);
+ data[1] = buf;
+
+ nrow = gtk_clist_prepend (clist, data);
+ gtk_clist_set_row_data (clist, nrow, it);
+ }
+
+ gtk_clist_select_row (clist, 0, 0);
+}
+
+static void objects_fill_foreach (gpointer key, gpointer value, gpointer datacl)
+{
+ GtkCList *clist = datacl;
+ ObjectInfo *obj = value;
+ char *data[3];
+ char buf[32];
+ gint row;
+
+ g_snprintf(buf, 32, "%p", key);
+ data[0] = g_strdup (buf);
+
+ data[1] = obj->type ? obj->type : "(\x3f\x3f\x3f)";
+
+ g_snprintf(buf, 32, "%d", obj->refcount);
+ data[2] = g_strdup (buf);
+
+ row = gtk_clist_append (clist, data);
+ gtk_clist_set_row_data (clist, row, obj);
+
+ g_free (data[0]);
+ g_free (data[2]);
+}
+
+static void
+objects_fill (ProcessWindow *pwin, GtkCList *clist)
+{
+ gtk_clist_clear (clist);
+ g_hash_table_foreach (pwin->objects, objects_fill_foreach, clist);
+ gtk_clist_sort (clist);
+ gtk_clist_select_row (clist, 0, 0);
+}
+
+static void
+objects_stack_run_command (ProcessWindow *pwin, ObjectHistoryItem *it, int frame)
+{
+ const char *filename;
+ char *functionname;
+ unsigned int line;
+
+ if (process_find_line (pwin->process, it->stack[frame],
+ &filename, &functionname, &line)) {
+
+ GString *command = g_string_new (NULL);
+ char *p = stack_command;
+ char buf[32];
+ char *args[3];
+
+ while (*p) {
+ if (*p == '%') {
+ switch (*++p) {
+ case 'f':
+ g_string_append (command, filename);
+ break;
+ case 'l':
+ snprintf(buf, 32, "%d", line);
+ g_string_append (command, buf);
+ break;
+ case '%':
+ g_string_append_c (command, '%');
+ break;
+ default:
+ g_string_append_c (command, '%');
+ g_string_append_c (command, *p);
+ }
+ } else
+ g_string_append_c (command, *p);
+ p++;
+ }
+
+ free (functionname);
+
+ args[0] = "/bin/sh";
+ args[1] = "-c";
+ args[2] = command->str;
+
+ if (gnome_execute_async (NULL, 3, args) == -1) {
+ show_error (pwin->main_window,
+ ERROR_MODAL, _("Executation of \"%s\" failed"),
+ command->str);
+ }
+
+ g_string_free (command, FALSE);
+ }
+}
+
+static gboolean
+objects_stack_button_press (GtkWidget *widget,
+ GdkEventButton *event,
+ ProcessWindow *pwin)
+{
+ if (event->window == GTK_CLIST (widget)->clist_window &&
+ event->type == GDK_2BUTTON_PRESS) {
+ int my_row;
+
+ if (!gtk_clist_get_selection_info (GTK_CLIST (widget),
+ event->x, event->y,
+ &my_row, NULL))
+ return FALSE;
+
+ if (my_row != -1) {
+ ObjectHistoryItem *it;
+ gint it_row;
+
+ g_return_val_if_fail (GTK_CLIST (pwin->objects_history_clist)->selection, FALSE);
+
+ it_row = GPOINTER_TO_INT (GTK_CLIST
+ (pwin->objects_history_clist)->selection->data);
+ it = gtk_clist_get_row_data (GTK_CLIST (pwin->objects_history_clist), it_row);
+
+ objects_stack_run_command (pwin, it, my_row);
+ }
+
+ g_signal_stop_emission_by_name (G_OBJECT (widget), "button_press_event");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+/************************************************************
* File Selection handling
************************************************************/
@@ -932,6 +1153,39 @@
}
}
+static void
+free_object_from_hashtable (gpointer key, gpointer value, gpointer data)
+{
+ object_info_free (value);
+}
+
+void
+generate_objects_cb (GtkWidget *widget)
+{
+ ProcessWindow *pwin = pwin_from_widget (widget);
+
+ if (pwin->process) {
+ process_stop_input (pwin->process);
+
+ gtk_clist_clear (GTK_CLIST (pwin->objects_clist));
+ gtk_clist_clear (GTK_CLIST (pwin->objects_history_clist));
+ gtk_clist_clear (GTK_CLIST (pwin->objects_stack_clist));
+
+ if (pwin->objects)
+ {
+ g_hash_table_foreach (pwin->objects, free_object_from_hashtable, NULL);
+ g_hash_table_destroy (pwin->objects);
+ }
+
+ pwin->objects = process_list_objects (pwin->process);
+
+ objects_fill (pwin, GTK_CLIST (pwin->objects_clist));
+ gtk_notebook_set_page (GTK_NOTEBOOK (pwin->main_notebook), 2);
+
+ process_start_input (pwin->process);
+ }
+}
+
void
generate_leak_cb (GtkWidget *widget)
{
@@ -1380,7 +1634,7 @@
gpointer user_data)
{
if (response_id == GTK_RESPONSE_OK)
- gtk_widget_destroy (dialog);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
}
void
@@ -1516,6 +1770,9 @@
pwin->bytes_per_label = glade_xml_get_widget (xml, "bytes-per-label");
pwin->total_bytes_label = glade_xml_get_widget (xml, "total-bytes-label");
+ pwin->live_objects_label = glade_xml_get_widget (xml, "live-objects-label");
+ pwin->max_live_objects_label = glade_xml_get_widget (xml, "max-live-objects-label");
+
pwin->profile_func_clist = glade_xml_get_widget (xml, "profile-func-clist");
pwin->profile_child_clist = glade_xml_get_widget (xml, "profile-child-clist");
pwin->profile_caller_clist = glade_xml_get_widget (xml, "profile-caller-clist");
@@ -1545,6 +1802,23 @@
gtk_signal_connect (GTK_OBJECT (pwin->leak_stack_clist), "button_press_event",
GTK_SIGNAL_FUNC (leak_stack_button_press), pwin);
+ pwin->objects_clist = glade_xml_get_widget (xml, "objects-clist");
+ pwin->objects_history_clist = glade_xml_get_widget (xml, "objects-history-clist");
+ pwin->objects_stack_clist = glade_xml_get_widget (xml, "objects-stack-clist");
+
+ gtk_clist_set_sort_column (GTK_CLIST (pwin->objects_clist), 1);
+
+ gtk_clist_set_column_width (GTK_CLIST (pwin->objects_clist), 1, 250);
+ gtk_clist_set_column_width (GTK_CLIST (pwin->objects_stack_clist), 0, 250);
+ gtk_clist_set_column_width (GTK_CLIST (pwin->objects_stack_clist), 2, 500);
+
+ gtk_signal_connect (GTK_OBJECT (pwin->objects_clist), "select_row",
+ GTK_SIGNAL_FUNC (objects_select_row), pwin);
+ gtk_signal_connect (GTK_OBJECT (pwin->objects_history_clist), "select_row",
+ GTK_SIGNAL_FUNC (objects_history_select_row), pwin);
+ gtk_signal_connect (GTK_OBJECT (pwin->objects_stack_clist), "button_press_event",
+ GTK_SIGNAL_FUNC (objects_stack_button_press), pwin);
+
pwin->usage_max_label = glade_xml_get_widget (xml, "usage-max-label");
pwin->usage_canvas = glade_xml_get_widget (xml, "usage-canvas");
@@ -1586,6 +1860,12 @@
vpaned = glade_xml_get_widget (xml, "leaks-vpaned");
gtk_paned_set_position (GTK_PANED (vpaned), 150);
+
+ vpaned = glade_xml_get_widget (xml, "objects-vpaned");
+ gtk_paned_set_position (GTK_PANED (vpaned), 125);
+
+ vpaned = glade_xml_get_widget (xml, "objects-second-vpaned");
+ gtk_paned_set_position (GTK_PANED (vpaned), 125);
glade_xml_signal_autoconnect (xml);
g_object_unref (G_OBJECT (xml));
Index: memintercept.c
===================================================================
RCS file: /cvs/gnome/memprof/memintercept.c,v
retrieving revision 1.14
diff -u -r1.14 memintercept.c
--- memintercept.c 15 Jul 2002 23:39:00 -0000 1.14
+++ memintercept.c 5 Aug 2002 17:14:12 -0000
@@ -38,6 +38,8 @@
#include <sys/types.h>
#include <sys/un.h>
+#include <glib-object.h>
+
static int initialized = 0;
static int (*old_execve) (const char *filename,
@@ -56,6 +58,10 @@
static void (*old_free) (void *ptr);
static void (*old__exit) (int status);
+static gpointer (*old_g_object_ref) (gpointer obj);
+static void (*old_g_object_unref) (gpointer obj);
+static GTypeInstance* (*old_g_type_create_instance) (GType type);
+
#define MAX_THREADS 128
static pthread_mutex_t malloc_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
@@ -647,6 +653,142 @@
(*old__exit) (status);
}
+gpointer
+__glib_g_object_ref (gpointer obj)
+{
+ gpointer result;
+ MIInfo info;
+ guint orc = 0;
+
+ if (!old_g_object_ref) {
+ g_warning ("old_g_object_ref == NULL");
+ return NULL;
+ }
+
+ if (!socket_path)
+ memprof_init();
+
+ if (tracing)
+ orc = ((GObject *) obj)->ref_count;
+
+ result = (*old_g_object_ref) (obj);
+
+ if (tracing) {
+ info.refcount.operation = MI_OBJ_REF;
+ info.refcount.old_ptr = NULL;
+ info.refcount.object = result;
+ info.refcount.old_refcount = orc;
+
+ stack_trace (&info);
+ }
+
+ return result;
+}
+
+gpointer
+g_object_ref (gpointer obj)
+{
+ return __glib_g_object_ref (obj);
+}
+
+void
+__glib_g_object_unref (gpointer obj)
+{
+ MIInfo info;
+ guint orc = 0;
+
+ if (!old_g_object_unref) {
+ g_warning ("old_g_object_unref == NULL");
+ return;
+ }
+
+ if (!socket_path)
+ memprof_init();
+
+ if (tracing)
+ orc = ((GObject *) obj)->ref_count;
+
+ (*old_g_object_unref) (obj);
+
+ if (tracing) {
+
+ info.refcount.operation = MI_OBJ_UNREF;
+ info.refcount.old_ptr = NULL;
+ info.refcount.object = obj;
+ info.refcount.old_refcount = orc;
+
+ stack_trace (&info);
+ }
+
+}
+
+void
+g_object_unref (gpointer obj)
+{
+ __glib_g_object_unref (obj);
+}
+
+gpointer
+__glib_g_type_create_instance (GType object_type)
+{
+ gpointer result;
+ MIInfo info;
+
+ if (!old_g_type_create_instance) {
+ g_warning ("old_g_type_create_instance == NULL");
+ return NULL;
+ }
+
+ if (!socket_path)
+ memprof_init();
+
+
+ result = (*old_g_type_create_instance) (object_type);
+
+ if (tracing) {
+ const gchar *type_name = g_type_name (G_TYPE_FROM_INSTANCE (result));
+ info.refcount.operation = MI_OBJ_NEW;
+ info.refcount.old_ptr = NULL;
+ info.refcount.object = result;
+ info.refcount.old_refcount = 0;
+
+ stack_trace (&info);
+
+ if (type_name)
+ {
+ unsigned int type_name_size = strlen (type_name) + 1;
+ MIInfo *tinfo;
+ char buffer[2048];
+ int i;
+
+ tinfo = (MIInfo *) buffer;
+
+ tinfo->objtype.pid = getpid();
+ tinfo->objtype.seqno = seqno++;
+ tinfo->objtype.operation = MI_OBJ_TYPE;
+ tinfo->objtype.object = result;
+ tinfo->objtype.type_name_size = type_name_size;
+ tinfo->objtype.type_name = NULL; /* not used here */
+
+ g_stpcpy (((char *) tinfo) + sizeof (MIInfo), type_name);
+
+ for (i=0; pids[i] && i<MAX_THREADS; i++)
+ if (pids[i] == tinfo->objtype.pid)
+ break;
+ write_all (outfds[i], (char *) tinfo, sizeof (MIInfo) + type_name_size);
+ }
+
+ }
+
+ return result;
+}
+
+GTypeInstance*
+g_type_create_instance (GType type)
+{
+ return __glib_g_type_create_instance (type);
+}
+
static void initialize () __attribute__ ((constructor));
static void initialize ()
@@ -661,6 +803,10 @@
old_vfork = dlsym(RTLD_NEXT, "__vfork");
old_clone = dlsym(RTLD_NEXT, "__clone");
old__exit = dlsym(RTLD_NEXT, "_exit");
+
+ old_g_object_ref = dlsym(RTLD_NEXT, "g_object_ref");
+ old_g_object_unref = dlsym(RTLD_NEXT, "g_object_unref");
+ old_g_type_create_instance = dlsym(RTLD_NEXT, "g_type_create_instance");
initialized = 1;
}
Index: memintercept.h
===================================================================
RCS file: /cvs/gnome/memprof/memintercept.h,v
retrieving revision 1.5
diff -u -r1.5 memintercept.h
--- memintercept.h 15 Jul 2002 23:39:00 -0000 1.5
+++ memintercept.h 5 Aug 2002 17:14:12 -0000
@@ -25,6 +25,8 @@
typedef struct _MIInfoAlloc MIInfoAlloc;
typedef struct _MIInfoFork MIInfoFork;
typedef struct _MIInfoExec MIInfoExec;
+typedef struct _MIInfoRefcount MIInfoRefcount;
+typedef struct _MIInfoObjType MIInfoObjType;
typedef enum {
MI_MALLOC,
@@ -34,7 +36,12 @@
MI_NEW,
MI_FORK,
MI_CLONE,
- MI_EXIT
+ MI_EXIT,
+
+ MI_OBJ_REF,
+ MI_OBJ_UNREF,
+ MI_OBJ_NEW,
+ MI_OBJ_TYPE
} MIOperation;
struct _MIInfoAny {
@@ -67,11 +74,32 @@
unsigned int seqno;
};
+struct _MIInfoRefcount {
+ MIOperation operation;
+ pid_t pid;
+ unsigned int seqno;
+ void *old_ptr; /* unused */
+ void *object;
+ unsigned int old_refcount;
+ unsigned int stack_size; /* must be here, like in MIInfoAlloc */
+};
+
+struct _MIInfoObjType {
+ MIOperation operation;
+ pid_t pid;
+ unsigned int seqno;
+ void *object;
+ unsigned int type_name_size;
+ char *type_name;
+};
+
union _MIInfo {
MIOperation operation;
MIInfoAny any;
MIInfoAlloc alloc;
MIInfoFork fork;
MIInfoExec exec;
+ MIInfoRefcount refcount;
+ MIInfoObjType objtype;
};
Index: memprof.glade
===================================================================
RCS file: /cvs/gnome/memprof/memprof.glade,v
retrieving revision 1.14
diff -u -r1.14 memprof.glade
--- memprof.glade 15 Jul 2002 23:39:00 -0000 1.14
+++ memprof.glade 5 Aug 2002 17:14:15 -0000
@@ -177,6 +177,23 @@
</child>
<child>
+ <widget class="GtkImageMenuItem" id="generate_objects_info1">
+ <property name="label" translatable="yes">Generate _GObjects Report</property>
+ <property name="visible">yes</property>
+ <property name="use_stock">no</property>
+ <property name="use_underline">yes</property>
+
+ <signal name="activate" handler="generate_objects_cb" />
+ <child internal-child="image">
+ <widget class="GtkImage" id="convertwidget4">
+ <property name="pixbuf">leak.xpm</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
<widget class="GtkMenuItem" id="separator8">
<property name="visible">yes</property>
</widget>
@@ -379,6 +396,17 @@
</child>
<child>
+ <widget class="button" id="button244">
+ <property name="tooltip" translatable="yes">Check Refcounting</property>
+ <property name="label" translatable="yes">Leaks</property>
+ <property name="icon">leak.xpm</property>
+ <property name="visible">yes</property>
+
+ <signal name="clicked" handler="generate_objects_cb" />
+ </widget>
+ </child>
+
+ <child>
<widget class="button" id="button3">
<property name="tooltip" translatable="yes">Save Report</property>
<property name="label" translatable="yes">Save</property>
@@ -650,6 +678,120 @@
</child>
<child>
+ <widget class="GtkHBox" id="hbox44">
+ <property name="border_width">4</property>
+ <property name="homogeneous">yes</property>
+ <property name="spacing">0</property>
+ <property name="visible">yes</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox55">
+ <property name="homogeneous">no</property>
+ <property name="spacing">0</property>
+ <property name="visible">yes</property>
+
+ <child>
+ <widget class="GtkLabel" id="label3030">
+ <property name="label" translatable="yes"># of Live GObjects:</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">no</property>
+ <property name="fill">no</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="live-objects-label">
+ <property name="label" translatable="yes">0</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">no</property>
+ <property name="fill">no</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">yes</property>
+ <property name="fill">yes</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox662">
+ <property name="homogeneous">no</property>
+ <property name="spacing">0</property>
+ <property name="visible">yes</property>
+
+ <child>
+ <widget class="GtkLabel" id="label43423">
+ <property name="label" translatable="yes">Max # of live GObjects:</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">no</property>
+ <property name="fill">no</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="max-live-objects-label">
+ <property name="label" translatable="yes">0</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">no</property>
+ <property name="fill">no</property>
+ </packing>
+ </child>
+
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">yes</property>
+ <property name="fill">yes</property>
+ </packing>
+ </child>
+
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">no</property>
+ <property name="fill">no</property>
+ </packing>
+ </child>
+
+ <child>
<widget class="GtkNotebook" id="main-notebook">
<property name="can_focus">yes</property>
<property name="show_tabs">yes</property>
@@ -1104,6 +1246,262 @@
<child>
<widget class="GtkLabel" id="label3">
<property name="label" translatable="yes">Leaks</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVPaned" id="objects-vpaned">
+ <property name="position">0</property>
+ <property name="visible">yes</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow55">
+ <property name="border_width">4</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="height-request">30</property>
+ <property name="visible">yes</property>
+
+ <child>
+ <widget class="GtkCList" id="objects-clist">
+ <property name="can_focus">yes</property>
+ <property name="column_widths">84,80,80</property>
+ <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+ <property name="show_titles">yes</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="n_columns">3</property>
+ <property name="visible">yes</property>
+
+ <child>
+ <widget class="GtkLabel" id="label404">
+ <property name="label" translatable="yes">Address</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label505">
+ <property name="label" translatable="yes">Type</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label606">
+ <property name="label" translatable="yes">Refcount</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child internal-child="hscrollbar">
+ <widget class="GtkHScrollbar" id="convertwidget8">
+ <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+
+ <child internal-child="vscrollbar">
+ <widget class="GtkVScrollbar" id="convertwidget9">
+ <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">no</property>
+ <property name="resize">no</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVPaned" id="objects-second-vpaned">
+ <property name="position">0</property>
+ <property name="visible">yes</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow5555">
+ <property name="border_width">4</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="height-request">30</property>
+ <property name="visible">yes</property>
+
+ <child>
+ <widget class="GtkCList" id="objects-history-clist">
+ <property name="can_focus">yes</property>
+ <property name="column_widths">84,80,80</property>
+ <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+ <property name="show_titles">yes</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="n_columns">2</property>
+ <property name="visible">yes</property>
+
+ <child>
+ <widget class="GtkLabel" id="label478">
+ <property name="label" translatable="yes">Operation</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label578">
+ <property name="label" translatable="yes">Old Refcount</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+
+ </widget>
+ </child>
+
+ <child internal-child="hscrollbar">
+ <widget class="GtkHScrollbar" id="convertwidget8">
+ <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+
+ <child internal-child="vscrollbar">
+ <widget class="GtkVScrollbar" id="convertwidget9">
+ <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">no</property>
+ <property name="resize">no</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow66661">
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="visible">yes</property>
+
+ <child>
+ <widget class="GtkCList" id="objects-stack-clist">
+ <property name="can_focus">yes</property>
+ <property name="column_widths">80,108,80</property>
+ <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+ <property name="show_titles">yes</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="n_columns">3</property>
+ <property name="visible">yes</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1289">
+ <property name="label" translatable="yes">Function</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1389">
+ <property name="label" translatable="yes">Line</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1489">
+ <property name="label" translatable="yes">File</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">no</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child internal-child="hscrollbar">
+ <widget class="GtkHScrollbar" id="convertwidget10">
+ <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+
+ <child internal-child="vscrollbar">
+ <widget class="GtkVScrollbar" id="convertwidget11">
+ <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
+ <property name="visible">yes</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">no</property>
+ <property name="resize">no</property>
+ </packing>
+ </child>
+
+
+ </widget>
+ </child>
+
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label33333">
+ <property name="label" translatable="yes">GObjects</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
<property name="wrap">no</property>
<property name="xalign">0.5</property>
Index: memprof.h
===================================================================
RCS file: /cvs/gnome/memprof/memprof.h,v
retrieving revision 1.6
diff -u -r1.6 memprof.h
--- memprof.h 15 Jul 2002 23:39:00 -0000 1.6
+++ memprof.h 5 Aug 2002 17:14:15 -0000
@@ -45,6 +45,23 @@
} Block;
typedef struct {
+ enum {
+ OH_REF,
+ OH_UNREF,
+ OH_NEW
+ } type;
+ guint old_refcount;
+ gint stack_size;
+ void **stack;
+} ObjectHistoryItem;
+
+typedef struct {
+ guint refcount;
+ gchar *type;
+ GSList *history;
+} ObjectInfo;
+
+typedef struct {
guint addr;
guint size;
gchar *name;
Index: process.c
===================================================================
RCS file: /cvs/gnome/memprof/process.c,v
retrieving revision 1.21
diff -u -r1.21 process.c
--- process.c 15 Jul 2002 23:39:00 -0000 1.21
+++ process.c 5 Aug 2002 17:14:17 -0000
@@ -119,6 +119,60 @@
}
/************************************************************
+ * ObjectInfo Manipulation
+ ************************************************************/
+
+static ObjectHistoryItem *
+object_history_item_duplicate (ObjectHistoryItem *it)
+{
+ ObjectHistoryItem *ret = g_new0 (ObjectHistoryItem, 1);
+ ret->type = it->type;
+ ret->old_refcount = it->old_refcount;
+ ret->stack_size = it->stack_size;
+ ret->stack = g_new0 (void *, it->stack_size);
+ memcpy (ret->stack, it->stack, ret->stack_size * sizeof (void *));
+ return ret;
+}
+
+static ObjectInfo *
+object_info_duplicate (ObjectInfo *obj)
+{
+ ObjectInfo *ret = g_new0 (ObjectInfo, 1);
+ GSList *li;
+ ret->refcount = obj->refcount;
+ ret->type = g_strdup (obj->type);
+ ret->history = NULL;
+
+ for (li = obj->history; li; li = li->next)
+ {
+ ret->history = g_slist_prepend (ret->history, object_history_item_duplicate (li->data));
+ }
+ ret->history = g_slist_reverse (ret->history);
+
+ return ret;
+}
+
+static void
+object_history_item_free (ObjectHistoryItem *it)
+{
+ g_free (it->stack);
+ g_free (it);
+}
+
+void
+object_info_free (ObjectInfo *obj)
+{
+ GSList *li;
+ for (li = obj->history; li; li = li->next)
+ {
+ object_history_item_free (li->data);
+ }
+ g_slist_free (obj->history);
+ g_free (obj->type);
+ g_free (obj);
+}
+
+/************************************************************
* Code to map addresses to object files
************************************************************/
@@ -405,6 +459,14 @@
}
static void
+process_free_object (gpointer key, gpointer value, gpointer data)
+{
+
+ object_info_free (value);
+
+}
+
+static void
process_duplicate_block (gpointer key, gpointer value, gpointer data)
{
GHashTable *new_table = data;
@@ -415,6 +477,15 @@
g_hash_table_insert (new_table, key, value);
}
+static void
+process_duplicate_object_info (gpointer key, gpointer value, gpointer data)
+{
+ GHashTable *new_table = data;
+ ObjectInfo *object = object_info_duplicate (value);
+
+ g_hash_table_insert (new_table, key, object);
+}
+
MPProcess *
process_duplicate (MPProcess *process)
{
@@ -424,6 +495,13 @@
process_duplicate_block,
new_process->block_table);
+
+ g_warning ("in process_duplicate");
+
+ g_hash_table_foreach (process->object_table,
+ process_duplicate_object_info,
+ new_process->object_table);
+
new_process->bytes_used = process->bytes_used;
new_process->n_allocations = process->n_allocations;
new_process->seqno = process->seqno;
@@ -462,6 +540,10 @@
g_hash_table_foreach (process->block_table, process_free_block, NULL);
g_hash_table_destroy (process->block_table);
process->block_table = g_hash_table_new (g_direct_hash, NULL);
+
+ g_hash_table_foreach (process->object_table, process_free_object, NULL);
+ g_hash_table_destroy (process->object_table);
+ process->object_table = g_hash_table_new (g_direct_hash, NULL);
/* FIXME: leak */
process->command_queue = NULL;
@@ -500,6 +582,58 @@
/* Handled before, ignore */
break;
+ case MI_OBJ_REF:
+ case MI_OBJ_UNREF:
+ case MI_OBJ_NEW:
+ {
+ ObjectInfo *obj = g_hash_table_lookup (process->object_table, info->refcount.object);
+ ObjectHistoryItem *h;
+ if (!obj)
+ {
+ obj = g_new0 (ObjectInfo, 1);
+ obj->refcount = info->refcount.old_refcount;
+ obj->type = NULL;
+ obj->history = NULL;
+
+ g_hash_table_insert (process->object_table, info->refcount.object, obj);
+ process->live_objects++;
+ process->max_live_objects = MAX (process->max_live_objects, process->live_objects);
+ }
+ h = g_new0 (ObjectHistoryItem, 1);
+ h->type = info->operation == MI_OBJ_NEW ? OH_NEW :
+ info->operation == MI_OBJ_REF ? OH_REF :
+ OH_UNREF;
+ h->old_refcount = info->refcount.old_refcount;
+ h->stack_size = info->alloc.stack_size;
+ h->stack = stack;
+ obj->history = g_slist_prepend (obj->history, h);
+ if (info->operation == MI_OBJ_NEW || info->operation == MI_OBJ_REF)
+ {
+ obj->refcount++;
+ }
+ else if (info->operation == MI_OBJ_UNREF)
+ {
+ obj->refcount--;
+ if (obj->refcount == 0)
+ {
+ process->live_objects--;
+ g_hash_table_remove (process->object_table, info->refcount.object);
+ object_info_free (obj);
+ }
+ }
+
+ }
+ break;
+
+ case MI_OBJ_TYPE:
+ {
+ ObjectInfo *obj = g_hash_table_lookup (process->object_table, info->objtype.object);
+ if (obj && obj->type == NULL)
+ {
+ obj->type = info->objtype.type_name;
+ }
+ }
+ break;
default: /* MALLOC / REALLOC / FREE */
if (info->alloc.old_ptr != NULL) {
block = g_hash_table_lookup (process->block_table, info->alloc.old_ptr);
@@ -574,8 +708,18 @@
info.operation == MI_REALLOC ||
info.operation == MI_FREE) {
stack = g_new (void *, info.alloc.stack_size);
- g_io_channel_read (source, (char *)stack, sizeof(void *) * info.alloc.stack_size, &count);
-
+ g_io_channel_read (source, (char *)stack,
+ sizeof(void *) * info.alloc.stack_size, &count);
+ } else if (info.operation == MI_OBJ_REF ||
+ info.operation == MI_OBJ_UNREF ||
+ info.operation == MI_OBJ_NEW) {
+ stack = g_new (void *, info.alloc.stack_size);
+ g_io_channel_read (source, (char *)stack,
+ sizeof(void *) * info.refcount.stack_size, &count);
+ } else if (info.operation == MI_OBJ_TYPE) {
+ info.objtype.type_name = g_new (char, info.objtype.type_name_size);
+ g_io_channel_read (source, info.objtype.type_name,
+ info.objtype.type_name_size, &count);
} else if (info.operation == MI_EXIT) {
process_set_status (input_process, MP_PROCESS_EXITING);
if (input_process->clone_of)
@@ -725,6 +869,7 @@
process->bytes_used = 0;
process->n_allocations = 0;
process->block_table = g_hash_table_new (g_direct_hash, NULL);
+ process->object_table = g_hash_table_new (g_direct_hash, NULL);
process->program_name = NULL;
process->input_channel = NULL;
@@ -889,3 +1034,22 @@
kill (process->pid, SIGTERM);
}
}
+
+static void
+process_list_objects_aux (gpointer key, gpointer value, gpointer data)
+{
+ GHashTable *ht = data;
+ ObjectInfo *obj = object_info_duplicate (value);
+
+ g_hash_table_insert (ht, key, obj);
+}
+
+GHashTable *
+process_list_objects (MPProcess *process)
+{
+ GHashTable *ret = g_hash_table_new (g_direct_hash, NULL);
+ g_hash_table_foreach (process->object_table, process_list_objects_aux, ret);
+ return ret;
+}
+
+
Index: process.h
===================================================================
RCS file: /cvs/gnome/memprof/process.h,v
retrieving revision 1.11
diff -u -r1.11 process.h
--- process.h 15 Jul 2002 23:39:00 -0000 1.11
+++ process.h 5 Aug 2002 17:14:17 -0000
@@ -77,6 +77,10 @@
GList *map_list;
GList *bad_pages;
GHashTable *block_table;
+
+ guint max_live_objects;
+ guint live_objects;
+ GHashTable *object_table;
GList *command_queue;
@@ -130,5 +134,8 @@
char ** process_parse_exec (const char *exec_string);
char * process_find_exec (char **args);
+
+GHashTable *process_list_objects (MPProcess *process);
+void object_info_free (ObjectInfo *obj);
#endif /* __PROCESS_H__ */
Index: server.c
===================================================================
RCS file: /cvs/gnome/memprof/server.c,v
retrieving revision 1.9
diff -u -r1.9 server.c
--- server.c 15 Jul 2002 23:39:00 -0000 1.9
+++ server.c 5 Aug 2002 17:14:18 -0000
@@ -506,6 +506,9 @@
case MI_FREE:
case MI_EXEC:
case MI_EXIT:
+ case MI_OBJ_REF:
+ case MI_OBJ_UNREF:
+ case MI_OBJ_NEW:
g_assert_not_reached ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]