gobject patch to track memory use
- From: Alexander Larsson <alexl redhat com>
- To: "desktop-devel-list gnome org" <desktop-devel-list gnome org>
- Subject: gobject patch to track memory use
- Date: Thu, 24 Feb 2005 18:23:39 +0100
I spent some day today hacking up a patch to gobject that lets you track
what types of GObjects are using memory.
It keeps a list of all live objects, and when you send the process a
SIGUSR2 it prints a memory profile. For the size it counts the basic
size of the object plus all private data registered with the object.
Furthermore it adds some API that lets you register a function to
calculate the size an object uses. This is useful for objects that own
memory allocations that are not GObjects. I also made a gtk+ patch using
this to track the real size of GdkPixbuf object.
Even without specific functions for all types this is quite useful, as
you can see the object counts. I've already detected some strange things
in nautilus with this. The top of the memory profile there looks like:
GtkImage: 231 allocated at 104 base size bytes, 23 kb total size
GstPadTemplate: 334 allocated at 76 base size bytes, 24 kb total size
GtkSeparatorMenuItem: 284 allocated at 96 base size bytes, 26 kb total size
NautilusIconCanvasItem: 502 allocated at 64 base size bytes, 31 kb total size
GtkAccelLabel: 306 allocated at 168 base size bytes, 50 kb total size
NautilusVFSFile: 1005 allocated at 128 base size bytes, 296 kb total size
GdkPixbuf: 340 allocated at 52 base size bytes, 6409 kb total size
(only NautilusVFSFile and GdkPixbuf have specific memuse functions here)
Maybe people want to play around a bit with this. It seems there is some
interest in memory profiling at the moment.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Alexander Larsson Red Hat, Inc
alexl redhat com alla lysator liu se
He's an immortal vegetarian farmboy in drag. She's a radical winged safe
cracker prone to fits of savage, blood-crazed rage. They fight crime!
Index: gobject/gtype.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/gtype.c,v
retrieving revision 1.78
diff -u -p -r1.78 gtype.c
--- gobject/gtype.c 1 Nov 2004 18:47:12 -0000 1.78
+++ gobject/gtype.c 24 Feb 2005 17:11:40 -0000
@@ -158,6 +158,7 @@ static void
TypeNode *node);
static gboolean type_node_is_a_L (TypeNode *node,
TypeNode *iface_node);
+static void install_mem_use_signal_handler (void);
/* --- enumeration --- */
@@ -191,6 +192,7 @@ struct _TypeNode
TypeData * volatile data;
GQuark qname;
GData *global_gdata;
+ GList *instances;
union {
IFaceEntry *iface_entries; /* for !iface types */
GType *prerequisistes;
@@ -279,6 +281,7 @@ struct _InstanceData
guint16 n_preallocs;
GInstanceInitFunc instance_init;
GMemChunk *mem_chunk;
+ GMemUseFunc mem_use;
};
union _TypeData
{
@@ -1575,6 +1578,11 @@ g_type_create_instance (GType type)
else
instance = g_malloc0 (total_instance_size); /* fine without read lock */
+
+ G_WRITE_LOCK (&type_rw_lock);
+ node->instances = g_list_prepend (node->instances, instance);
+ G_WRITE_UNLOCK (&type_rw_lock);
+
if (node->data->instance.private_size)
instance_real_class_set (instance, class);
for (i = node->n_supers; i > 0; i--)
@@ -1625,7 +1633,12 @@ g_type_free_instance (GTypeInstance *ins
instance->g_class = NULL;
#ifdef G_ENABLE_DEBUG
memset (instance, 0xaa, type_total_instance_size_I (node)); /* debugging hack */
-#endif
+#endif
+
+ G_WRITE_LOCK (&type_rw_lock);
+ node->instances = g_list_remove (node->instances, instance);
+ G_WRITE_UNLOCK (&type_rw_lock);
+
if (node->data->instance.n_preallocs)
{
G_WRITE_LOCK (&type_rw_lock);
@@ -2242,6 +2255,24 @@ g_type_register_fundamental (GType
return NODE_TYPE (node);
}
+void
+g_type_register_memuse_function (GType type,
+ GMemUseFunc memuse)
+{
+ TypeNode *node;
+
+ node = lookup_type_node_I (type);
+
+ if (node && node->is_instantiatable && node->data != NULL)
+ {
+ G_WRITE_LOCK (&type_rw_lock);
+
+ node->data->instance.mem_use = memuse;
+
+ G_WRITE_UNLOCK (&type_rw_lock);
+ }
+}
+
GType
g_type_register_static (GType parent_type,
const gchar *type_name,
@@ -3477,6 +3508,8 @@ g_type_init_with_debug_flags (GTypeDebug
/* Signal system
*/
g_signal_init ();
+
+ install_mem_use_signal_handler ();
G_UNLOCK (type_init_lock);
}
@@ -3579,4 +3612,134 @@ g_type_instance_get_private (GTypeInstan
}
return G_STRUCT_MEMBER_P (instance, offset);
+}
+
+
+typedef struct {
+ const char *name;
+ gsize instance_size;
+ int n_allocated;
+ gsize total_size;
+} NodeMemUse;
+
+static gint
+compare_memuse (gconstpointer a,
+ gconstpointer b)
+{
+ const NodeMemUse *m1 = a;
+ const NodeMemUse *m2 = b;
+ gsize s1, s2;
+
+ s1 = m1->total_size;
+ s2 = m2->total_size;
+ if (s1 < s2)
+ return -1;
+ if (s1 == s2)
+ return 0;
+ return 1;
+}
+
+static void
+report_mem_use_for_node (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ TypeNode *node;
+ gsize total_instance_size;
+ gsize total_size;
+ int n_allocated;
+ GType type;
+ GList **list, *l;
+ NodeMemUse *memuse;
+ int i;
+
+ list = user_data;
+
+ type = (GType)value;
+ node = lookup_type_node_I (type);
+ if (node == NULL ||
+ !node->is_instantiatable ||
+ node->data == NULL)
+ return;
+
+ total_instance_size = type_total_instance_size_I (node);
+ if (node->data->instance.private_size)
+ total_instance_size = ALIGN_STRUCT (total_instance_size);
+
+ memuse = g_new (NodeMemUse, 1);
+ memuse->name = NODE_NAME(node);
+ memuse->instance_size = total_instance_size;
+
+ total_size = 0;
+ n_allocated = 0;
+ for (l = node->instances; l != NULL; l = l->next)
+ {
+ GTypeInstance *instance = l->data;
+
+ for (i = 0; i < node->n_supers; i++) {
+ GType instance_type;
+ TypeNode *instance_node;
+
+ instance_type = node->supers[i];
+ instance_node = lookup_type_node_I (instance_type);
+
+ if (instance_node != NULL &&
+ instance_node->is_instantiatable &&
+ instance_node->data != NULL &&
+ instance_node->data->instance.mem_use != NULL)
+ total_size += instance_node->data->instance.mem_use (instance);
+ }
+
+ n_allocated ++;
+ }
+ total_size += n_allocated * total_instance_size;
+
+ memuse->n_allocated = n_allocated;
+ memuse->total_size = total_size;
+
+ *list = g_list_append (*list, memuse);
+}
+
+static void
+report_mem_use (int i)
+{
+ GList *list, *l;
+ NodeMemUse *memuse;
+
+ G_READ_LOCK (&type_rw_lock);
+ list = NULL;
+ g_hash_table_foreach (static_type_nodes_ht, report_mem_use_for_node, &list);
+
+ list = g_list_sort (list, compare_memuse);
+
+ for (l = list; l != NULL; l = l->next)
+ {
+ memuse = l->data;
+
+ g_print ("%s: %d allocated at %lu base size bytes, %lu kb total size\n",
+ memuse->name,
+ memuse->n_allocated,
+ (gulong) memuse->instance_size,
+ (gulong) (memuse->total_size / 1024));
+
+ g_free (memuse);
+ }
+ g_list_free (list);
+
+ G_READ_UNLOCK (&type_rw_lock);
+
+}
+
+#include <signal.h>
+
+static void
+install_mem_use_signal_handler (void)
+{
+ struct sigaction action;
+
+ action.sa_handler = report_mem_use;
+ sigemptyset (&action.sa_mask);
+ action.sa_flags = 0;
+
+ sigaction(SIGUSR2, &action, NULL);
}
Index: gobject/gtype.h
===================================================================
RCS file: /cvs/gnome/glib/gobject/gtype.h,v
retrieving revision 1.60
diff -u -p -r1.60 gtype.h
--- gobject/gtype.h 24 Oct 2004 01:22:29 -0000 1.60
+++ gobject/gtype.h 24 Feb 2005 17:11:40 -0000
@@ -221,6 +221,7 @@ typedef gboolean (*GTypeClassCacheFunc)
GTypeClass *g_class);
typedef void (*GTypeInterfaceCheckFunc) (gpointer check_data,
gpointer g_iface);
+typedef gsize (*GMemUseFunc) (GTypeInstance *instance);
typedef enum /*< skip >*/
{
G_TYPE_FLAG_CLASSED = (1 << 0),
@@ -310,6 +311,8 @@ void g_type_class_add_private
gsize private_size);
gpointer g_type_instance_get_private (GTypeInstance *instance,
GType private_type);
+void g_type_register_memuse_function (GType type,
+ GMemUseFunc memuse);
/* --- GType boilerplate --- */
Index: gdk-pixbuf/gdk-pixbuf.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf.c,v
retrieving revision 1.64
diff -u -p -r1.64 gdk-pixbuf.c
--- gdk-pixbuf/gdk-pixbuf.c 5 Nov 2004 01:43:31 -0000 1.64
+++ gdk-pixbuf/gdk-pixbuf.c 24 Feb 2005 17:11:53 -0000
@@ -59,6 +59,12 @@ enum
static gpointer parent_class;
+static gsize
+pixbuf_memuse (GdkPixbuf *pixbuf)
+{
+ return pixbuf->rowstride * pixbuf->height;
+}
+
GType
gdk_pixbuf_get_type (void)
{
@@ -80,6 +86,8 @@ gdk_pixbuf_get_type (void)
object_type = g_type_register_static (G_TYPE_OBJECT,
"GdkPixbuf",
&object_info, 0);
+ g_type_register_memuse_function (object_type,
+ (GMemUseFunc) pixbuf_memuse);
}
return object_type;
Index: libnautilus-private/nautilus-file.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-file.c,v
retrieving revision 1.362
diff -u -p -r1.362 nautilus-file.c
--- libnautilus-private/nautilus-file.c 22 Feb 2005 10:41:46 -0000 1.362
+++ libnautilus-private/nautilus-file.c 24 Feb 2005 17:20:23 -0000
@@ -132,6 +132,39 @@ static gboolean update_info_and_name
static char * nautilus_file_get_display_name_nocopy (NautilusFile *file);
static char * nautilus_file_get_display_name_collation_key (NautilusFile *file);
+static gsize
+file_memuse (NautilusFile *file)
+{
+ gsize size;
+ NautilusFileDetails *details = file->details;
+ GList *l;
+
+ if (details == NULL)
+ return 0;
+
+ size = 0;
+
+ size += eel_strlen (details->relative_uri) + 1;
+ size += eel_strlen (details->cached_display_name) + 1;
+ size += eel_strlen (details->display_name_collation_key) + 1;
+ if (details->info)
+ size += sizeof(GnomeVFSFileInfo);
+
+ for (l = details->mime_list; l != NULL; l = l->next) {
+ size += sizeof(GList);
+ size += eel_strlen (l->data) + 1;
+ }
+
+ size += eel_strlen (details->top_left_text);
+ size += eel_strlen (details->display_name);
+ size += eel_strlen (details->custom_icon);
+ size += eel_strlen (details->activation_uri);
+ size += eel_strlen (details->guessed_mime_type);
+
+ return size;
+}
+
+
GType
nautilus_file_get_type (void)
{
@@ -162,6 +195,8 @@ nautilus_file_get_type (void)
g_type_add_interface_static (type,
NAUTILUS_TYPE_FILE_INFO,
&file_info_iface_info);
+ g_type_register_memuse_function (type,
+ (GMemUseFunc) file_memuse);
}
return type;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]