[glib] Add dtrace and systemtap support for gobject



commit 8e41be13efe06a0bbd89beefc6e7ae7279b56834
Author: Alexander Larsson <alexl redhat com>
Date:   Fri Jan 1 21:39:52 2010 +0100

    Add dtrace and systemtap support for gobject
    
    This adds static markers and systemtap tapsets for:
    
    * type creation
    * object lifetimes (creation, ref, unref, dispose, finalize)
    * signal creation and emission
    
    Signal emissions and finalization marker have a corresponding
    *_end (or *-end in dtrace) version that is when the corresponding
    operation is finished.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=606044

 configure.in             |    1 +
 gobject/Makefile.am      |   22 +++++
 gobject/gobject.c        |   28 +++++--
 gobject/gobject.stp.in   |  199 ++++++++++++++++++++++++++++++++++++++++++++++
 gobject/gobject_probes.d |   13 +++
 gobject/gobject_trace.h  |   43 ++++++++++
 gobject/gsignal.c        |   11 ++-
 gobject/gtype.c          |    9 ++-
 8 files changed, 316 insertions(+), 10 deletions(-)
---
diff --git a/configure.in b/configure.in
index 17214d9..af733d8 100644
--- a/configure.in
+++ b/configure.in
@@ -3592,6 +3592,7 @@ glib/tests/Makefile
 gmodule/Makefile
 gmodule/gmoduleconf.h
 gobject/Makefile
+gobject/gobject.stp
 gobject/glib-mkenums
 gobject/tests/Makefile
 gthread/Makefile
diff --git a/gobject/Makefile.am b/gobject/Makefile.am
index 9abcabc..6bcd5ae 100644
--- a/gobject/Makefile.am
+++ b/gobject/Makefile.am
@@ -6,6 +6,8 @@ include $(top_srcdir)/Makefile.decl
 
 SUBDIRS = . tests
 
+CLEANFILES=
+
 if HAVE_THREADS
 THREAD_FLAGS=-DG_THREADS_MANDATORY
 endif
@@ -120,11 +122,13 @@ gobject_private_h_sources =     \
 
 # GObject library C sources to build the library from
 gobject_c_sources = \
+	gobject_probes.d	\
 	gatomicarray.c		\
 	gboxed.c		\
 	gclosure.c		\
 	genums.c		\
 	gobject.c		\
+	gobject_trace.h		\
 	gparam.c		\
 	gparamspecs.c		\
 	gsignal.c		\
@@ -140,6 +144,24 @@ gobject_c_sources = \
 # these sources (also mentioned above) are generated.
 BUILT_SOURCES = gmarshal.h gmarshal.c gobjectalias.h gobjectaliasdef.c
 
+if ENABLE_DTRACE
+gobject_probes.h: gobject_probes.d Makefile
+	$(DTRACE) -C -h -s $< -o $  tmp
+	sed -e "s,define STAP_HAS_SEMAPHORES 1,undef STAP_HAS_SEMAPHORES," < $  tmp > $@ && rm -f $  tmp
+gobject_probes.o: gobject_probes.d Makefile
+	$(DTRACE) -G -s $< -o $@
+BUILT_SOURCES += gobject_probes.h gobject_probes.o
+CLEANFILES += gobject_probes.h
+libgobject_2_0_la_LIBADD += gobject_probes.o
+endif
+
+if ENABLE_SYSTEMTAP
+tapset_in_files = gobject.stp.in
+tapsetdir   = $(DESTDIR)@ABS_TAPSET_DIR@
+tapset_DATA = $(tapset_in_files:.stp.in=.stp)
+EXTRA_DIST += $(tapset_in_files)
+endif
+
 # non-header sources (headers should be specified in the above variables)
 # that don't serve as direct make target sources, i.e. they don't have
 # their own .lo rules and don't get publically installed
diff --git a/gobject/gobject.c b/gobject/gobject.c
index 56e6f9e..ddfb47b 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -33,6 +33,7 @@
 #include "gsignal.h"
 #include "gparamspecs.h"
 #include "gvaluetypes.h"
+#include "gobject_trace.h"
 #include "gobjectalias.h"
 
 /* This should be included after gobjectalias.h (or pltcheck.sh will fail) */
@@ -817,7 +818,9 @@ g_object_run_dispose (GObject *object)
   g_return_if_fail (object->ref_count > 0);
 
   g_object_ref (object);
+  TRACE (GOBJECT_OBJECT_DISPOSE(object,G_TYPE_FROM_INSTANCE(object), 0));
   G_OBJECT_GET_CLASS (object)->dispose (object);
+  TRACE (GOBJECT_OBJECT_DISPOSE_END(object,G_TYPE_FROM_INSTANCE(object), 0));
   g_object_unref (object);
 }
 
@@ -2406,7 +2409,9 @@ g_object_ref (gpointer _object)
 
   if (old_val == 1 && OBJECT_HAS_TOGGLE_REF (object))
     toggle_refs_notify (object, FALSE);
-  
+
+  TRACE (GOBJECT_OBJECT_REF(object,G_TYPE_FROM_INSTANCE(object),old_val));
+
   return object;
 }
 
@@ -2422,7 +2427,6 @@ g_object_unref (gpointer _object)
 {
   GObject *object = _object;
   gint old_ref;
-  gboolean is_zero;
   
   g_return_if_fail (G_IS_OBJECT (object));
   g_return_if_fail (object->ref_count > 0);
@@ -2443,6 +2447,8 @@ g_object_unref (gpointer _object)
       if (!g_atomic_int_compare_and_exchange ((int *)&object->ref_count, old_ref, old_ref - 1))
 	goto retry_atomic_decrement1;
 
+      TRACE (GOBJECT_OBJECT_UNREF(object,G_TYPE_FROM_INSTANCE(object),old_ref));
+
       /* if we went from 2->1 we need to notify toggle refs if any */
       if (old_ref == 2 && has_toggle_ref) /* The last ref being held in this case is owned by the toggle_ref */
 	toggle_refs_notify (object, TRUE);
@@ -2450,7 +2456,9 @@ g_object_unref (gpointer _object)
   else
     {
       /* we are about tp remove the last reference */
+      TRACE (GOBJECT_OBJECT_DISPOSE(object,G_TYPE_FROM_INSTANCE(object), 1));
       G_OBJECT_GET_CLASS (object)->dispose (object);
+      TRACE (GOBJECT_OBJECT_DISPOSE_END(object,G_TYPE_FROM_INSTANCE(object), 1));
 
       /* may have been re-referenced meanwhile */
     retry_atomic_decrement2:
@@ -2463,25 +2471,33 @@ g_object_unref (gpointer _object)
           if (!g_atomic_int_compare_and_exchange ((int *)&object->ref_count, old_ref, old_ref - 1))
 	    goto retry_atomic_decrement2;
 
+	  TRACE (GOBJECT_OBJECT_UNREF(object,G_TYPE_FROM_INSTANCE(object),old_ref));
+
           /* if we went from 2->1 we need to notify toggle refs if any */
           if (old_ref == 2 && has_toggle_ref) /* The last ref being held in this case is owned by the toggle_ref */
 	    toggle_refs_notify (object, TRUE);
 
 	  return;
 	}
-      
+
       /* we are still in the process of taking away the last ref */
       g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL);
       g_signal_handlers_destroy (object);
       g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL);
       
       /* decrement the last reference */
-      is_zero = g_atomic_int_dec_and_test ((int *)&object->ref_count);
-      
+      old_ref = g_atomic_int_exchange_and_add ((int *)&object->ref_count, -1);
+
+      TRACE (GOBJECT_OBJECT_UNREF(object,G_TYPE_FROM_INSTANCE(object),old_ref));
+
       /* may have been re-referenced meanwhile */
-      if (G_LIKELY (is_zero)) 
+      if (G_LIKELY (old_ref == 1))
 	{
+	  TRACE (GOBJECT_OBJECT_FINALIZE(object,G_TYPE_FROM_INSTANCE(object)));
           G_OBJECT_GET_CLASS (object)->finalize (object);
+
+	  TRACE (GOBJECT_OBJECT_FINALIZE_END(object,G_TYPE_FROM_INSTANCE(object)));
+
 #ifdef	G_ENABLE_DEBUG
           IF_DEBUG (OBJECTS)
 	    {
diff --git a/gobject/gobject.stp.in b/gobject/gobject.stp.in
new file mode 100644
index 0000000..edcdb50
--- /dev/null
+++ b/gobject/gobject.stp.in
@@ -0,0 +1,199 @@
+global gtypes
+global gtypenames
+global gsignalnames
+
+/* These are needed to keep track of gtype and signal names for the below
+ * probes.
+ */
+probe process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("type__new")
+{
+  gtypes[pid(),user_string($arg1)] = $arg3;
+  gtypenames[pid(),$arg3] = user_string($arg1);
+}
+probe process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("signal__new")
+{
+  gsignalnames[pid(),$arg1] = user_string($arg2);
+}
+
+/**
+ * probe gobject.type_new - Called when any entity registered with the #GType system is created
+ * @name: String name of type
+ * @parent_gtype: The parent #GType of this type
+ * @gtype: The #GType for this type
+ */
+probe gobject.type_new = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("type__new")
+{
+  name = user_string($arg1); 
+  parent_gtype = $arg2; 
+  gtype = $arg3; 
+  probestr = sprintf("gobject.type_new(%s, %d) -> %d", name, parent_gtype, gtype);
+}
+
+/**
+ * probe gobject.object_new - Called when a #GObject is created
+ * @object: Raw pointer to object
+ * @gtype: #GType for this object
+ * @type: String name of object type
+ */
+probe gobject.object_new = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("object__new")
+{
+  object = $arg1; 
+  gtype = $arg2; 
+  type = gtypenames[pid(),$arg2]; 
+  probestr = sprintf("gobject.object_new(%s) -> %p", type, object);
+}
+
+/**
+ * probe gobject.object_ref - Called when a new reference is added to a #GObject
+ * @object: Raw pointer to object
+ * @gtype: #GType for this object
+ * @type: String name of object type
+ * @old_refcount: Original value of the reference count
+ * @refcount: New value of the reference count
+ */
+probe gobject.object_ref = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("object__ref")
+{
+  object = $arg1; 
+  gtype = $arg2; 
+  type = gtypenames[pid(),gtype]; 
+  old_refcount = $arg3; 
+  refcount = old_refcount+1; 
+  probestr = sprintf("gobject.object_ref(%p[%s]) -> %d", object, type, refcount);
+}
+
+/**
+ * probe gobject.object_unref - Called when a reference is removed from a #GObject
+ * @object: Raw pointer to object
+ * @gtype: #GType for this object
+ * @type: String name of object type
+ * @old_refcount: Original value of the reference count
+ */
+probe gobject.object_unref = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("object__unref")
+{
+  object = $arg1; 
+  gtype = $arg2; 
+  type = gtypenames[pid(),gtype]; 
+  old_refcount = $arg3; 
+  refcount = old_refcount-1; 
+  probestr = sprintf("gobject.object_unref(%p [%s]) -> %d", object, type, refcount);
+}
+
+/**
+ * probe gobject.object_dispose - Called when a g_object_dispose() run for a #GObject is initiated
+ * @object: Raw pointer to object
+ * @gtype: #GType for this object
+ * @type: String name of object type
+ * @last_unref: FIXME
+ */
+probe gobject.object_dispose = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("object__dispose")
+{
+  object = $arg1; 
+  gtype = $arg2; 
+  type = gtypenames[pid(),$arg2]; 
+  last_unref = $arg3; 
+  probestr = sprintf("gobject.object_dispose(%p[%s])", object, type);
+}
+
+/**
+ * probe gobject.object_dispose_end - Called when a g_object_dispose() run for a #GObject is completed
+ * @object: Raw pointer to object
+ * @gtype: #GType for this object
+ * @type: String name of object type
+ * @last_unref: FIXME
+ */
+probe gobject.object_dispose_end = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("object__dispose__end")
+{
+  object = $arg1; 
+  gtype = $arg2; 
+  type = gtypenames[pid(),$arg2]; 
+  last_unref = $arg3; 
+  probestr = sprintf("gobject.object_dispose_end(%p[%s])", object, type);
+}
+
+/**
+ * probe gobject.object_finalize - Called when finalization for a #GObject is started
+ * @object: Raw pointer to object
+ * @gtype: #GType for this object
+ * @type: String name of object type
+ */
+probe gobject.object_finalize = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("object__finalize")
+{
+  object = $arg1; 
+  gtype = $arg2; 
+  type = gtypenames[pid(),$arg2]; 
+  probestr = sprintf("gobject.object_finalize(%p[%s])", object, type);
+}
+
+/**
+ * probe gobject.object_finalize - Called when finalization for a #GObject is completed
+ * @object: Raw pointer to object
+ * @gtype: #GType for this object
+ * @type: String name of object type
+ */
+probe gobject.object_finalize_end = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("object__finalize__end")
+{
+  object = $arg1; 
+  gtype = $arg2; 
+  type = gtypenames[pid(),$arg2]; 
+  probestr = sprintf("gobject.object_finalize_end(%p[%s])", object, type);
+}
+
+/**
+ * probe gobject.signal_new - Called when a new signal is registered for a #GObject
+ * @gsignal: Integer value for this signal
+ * @name: String name for this signal
+ * @gtype: #GType for the type which will gain the new signal
+ * @type: String name of the type which will gain the new signal
+ */
+probe gobject.signal_new = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("signal__new")
+{
+  gsignal = $arg1; 
+  name = user_string($arg2); 
+  gtype = $arg3; 
+  type = gtypenames[pid(),$arg3]; 
+  probestr = sprintf("gobject.signal_new(%s, %s) -> %d", name, type, gsignal);
+}
+
+/**
+ * probe gobject.signal_emit - Called when a signal emission for a #GObject is started
+ * @gsignal: Integer value for this signal
+ * @detail: String containing signal "detail"
+ * @signal: String name of the signal
+ * @object: Raw pointer for object emitting signal
+ * @gtype: #GType for the type emitting the signal
+ * @type: String name of the type emitting the signal
+ */
+probe gobject.signal_emit = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("signal__emit")
+{
+  gsignal = $arg1; 
+  detail = $arg2; 
+  signal = gsignalnames[pid(),$arg1]; 
+  if (detail != 0)
+    signal = signal . "::" . gquarks[pid(), detail]
+  object = $arg3; 
+  gtype = $arg4; 
+  type = gtypenames[pid(),$arg4]; 
+  probestr = sprintf("gobject.signal_emit(%p[%s], %s)", object, type, signal);
+}
+
+/**
+ * probe gobject.signal_emit_end - Called when a signal emission for a #GObject is completed
+ * @gsignal: Integer value for this signal
+ * @detail: String containing signal "detail"
+ * @signal: String name of the signal
+ * @object: Raw pointer for object emitting signal
+ * @gtype: #GType for the type emitting the signal
+ * @type: String name of the type emitting the signal
+ */
+probe gobject.signal_emit_end = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgobject-2 0 so 0  LT_CURRENT@  LT_REVISION@").mark("signal__emit__end")
+{
+  gsignal = $arg1; 
+  detail = $arg2; 
+  signal = gsignalnames[pid(),$arg1]; 
+  if (detail != 0)
+    signal = signal . "::" . gquarks[pid(), detail]
+  object = $arg3; 
+  gtype = $arg4; 
+  type = gtypenames[pid(),$arg4]; 
+  probestr = sprintf("gobject.signal_emit_end(%p[%s], %s)", object, type, signal);
+}
diff --git a/gobject/gobject_probes.d b/gobject/gobject_probes.d
new file mode 100644
index 0000000..044e68a
--- /dev/null
+++ b/gobject/gobject_probes.d
@@ -0,0 +1,13 @@
+provider gobject {
+	probe type__new(char *, unsigned long, unsigned long);
+	probe object__new(void*, unsigned long);
+	probe object__ref(void*, unsigned long, unsigned int);
+	probe object__unref(void*, unsigned long, unsigned int);
+	probe object__dispose(void*, unsigned long, unsigned int);
+	probe object__dispose__end(void*, unsigned long, unsigned int);
+	probe object__finalize(void*, unsigned long);
+	probe object__finalize__end(void*, unsigned long);
+	probe signal__new(unsigned int, char *, unsigned long)
+	probe signal__emit(unsigned int, unsigned int, void *, unsigned long)
+	probe signal__emit__end(unsigned int, unsigned int, void *, unsigned long)
+};
diff --git a/gobject/gobject_trace.h b/gobject/gobject_trace.h
new file mode 100644
index 0000000..292a0e8
--- /dev/null
+++ b/gobject/gobject_trace.h
@@ -0,0 +1,43 @@
+/* GLIB - Library of useful routines for C programming
+ * 
+ * Copyright (C) 2009,2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+ 
+#ifndef __GOBJECTTRACE_H__
+#define __GOBJECTTRACE_H__
+
+#ifndef SIZEOF_CHAR
+#error "config.h must be included prior to gobject_trace.h"
+#endif
+
+#ifdef HAVE_DTRACE
+
+/* include the generated probes header and put markers in code */
+#include "gobject_probes.h"
+#define TRACE(probe) probe
+
+#else
+
+/* Wrap the probe to allow it to be removed when no systemtap available */
+#define TRACE(probe)
+
+#endif
+
+#endif /* __GOBJECTTRACE_H__ */
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
index a5d35eb..9208b6e 100644
--- a/gobject/gsignal.c
+++ b/gobject/gsignal.c
@@ -36,6 +36,7 @@
 #include "gboxed.h"
 #include "gobject.h"
 #include "genums.h"
+#include "gobject_trace.h"
 #include "gobjectalias.h"
 
 
@@ -1608,6 +1609,8 @@ g_signal_newv (const gchar       *signal_name,
       node->name = g_intern_string (name);
       key.quark = g_quark_from_string (name);
       g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key);
+
+      TRACE(GOBJECT_SIGNAL_NEW(signal_id, name, itype));
     }
   node->destroyed = FALSE;
   node->test_class_offset = 0;
@@ -3124,7 +3127,9 @@ signal_emit_unlocked_R (SignalNode   *node,
 	G_BREAKPOINT ();
     }
 #endif	/* G_ENABLE_DEBUG */
-  
+
+  TRACE(GOBJECT_SIGNAL_EMIT(node->signal_id, detail, instance, G_TYPE_FROM_INSTANCE (instance)));
+
   SIGNAL_LOCK ();
   signal_id = node->signal_id;
   if (node->flags & G_SIGNAL_NO_RECURSE)
@@ -3382,7 +3387,9 @@ signal_emit_unlocked_R (SignalNode   *node,
   SIGNAL_UNLOCK ();
   if (accumulator)
     g_value_unset (&accu);
-  
+
+  TRACE(GOBJECT_SIGNAL_EMIT_END(node->signal_id, detail, instance, G_TYPE_FROM_INSTANCE (instance)));
+
   return return_value_altered;
 }
 
diff --git a/gobject/gtype.c b/gobject/gtype.c
index fc95253..49b563a 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -32,6 +32,7 @@
 #include "gbsearcharray.h"
 #include "gobjectalias.h"
 #include "gatomicarray.h"
+#include "gobject_trace.h"
 
 
 /**
@@ -481,7 +482,9 @@ type_node_any_new_W (TypeNode             *pnode,
       pnode->children = g_renew (GType, pnode->children, pnode->n_children);
       pnode->children[i] = type;
     }
-  
+
+  TRACE(GOBJECT_TYPE_NEW(name, node->supers[1], type));
+
   node->plugin = plugin;
   node->n_children = 0;
   node->children = NULL;
@@ -1883,7 +1886,9 @@ g_type_create_instance (GType type)
   instance->g_class = class;
   if (node->data->instance.instance_init)
     node->data->instance.instance_init (instance, class);
-  
+
+  TRACE(GOBJECT_OBJECT_NEW(instance, type));
+
   return instance;
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]