Support for gobject tracking in memprof



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]