diff --git a/configure.in b/configure.in
index 6cc3bc948..17214d9a7 100644
--- a/configure.in
+++ b/configure.in
@@ -2773,6 +2773,58 @@ fi
AM_CONDITIONAL(ENABLE_MAN, test x$enable_man != xno)
+dnl
+dnl Tracing
+dnl
+
+AC_ARG_ENABLE([dtrace],
+ [AS_HELP_STRING([--enable-dtrace],
+ [Enable inclusion of dtrace trace support])])
+have_dtrace=no
+AC_MSG_CHECKING([whether to include dtrace tracing support])
+if test "x$enable_dtrace" != xno; then
+ AC_MSG_RESULT([yes])
+ AC_CHECK_PROGS(DTRACE, dtrace)
+ if test -z "$DTRACE"; then
+ if test "x$enable_dtrace" = xyes; then
+ AC_MSG_ERROR([dtrace not found])
+ fi
+ fi
+ AC_CHECK_HEADER([sys/sdt.h],have_dtrace=yes,
+ [if test "x$enable_dtrace" = xyes; then
+ AC_MSG_ERROR([dtrace support needs sys/sdt.h header])
+ fi])
+else
+ AC_MSG_RESULT([no])
+fi
+if test "x$have_dtrace" = xyes; then
+ AC_DEFINE([HAVE_DTRACE], [1], [Define to 1 if using dtrace probes.])
+fi
+AM_CONDITIONAL([ENABLE_DTRACE], [test x$have_dtrace = xyes ])
+
+AC_MSG_CHECKING([whether to include systemtap tracing support])
+AC_ARG_ENABLE([systemtap],
+ [AS_HELP_STRING([--enable-systemtap],
+ [Enable inclusion of systemtap trace support])])
+have_systemtap=no
+if test "x$enable_systemtap" != xno -a "x$have_dtrace" = xyes; then
+ have_systemtap=yes
+fi
+AC_MSG_RESULT(${have_systemtap})
+
+AM_CONDITIONAL([ENABLE_SYSTEMTAP], [test x$have_systemtap = xyes])
+
+AC_ARG_WITH([tapset-install-dir],
+ [AS_HELP_STRING([--with-tapset-install-dir],
+ [The absolute path where the systemtap tapsets will be installed])],
+ [if test "x${withval}" = x; then
+ ABS_TAPSET_DIR="\$(datadir)/systemtap/tapset"
+ else
+ ABS_TAPSET_DIR="${withval}"
+ fi],
+ [ABS_TAPSET_DIR="\$(datadir)/systemtap/tapset"])
+AC_SUBST(ABS_TAPSET_DIR)
+
dnl ******************************
dnl *** output the whole stuff ***
dnl ******************************
@@ -3531,6 +3583,7 @@ build/win32/Makefile
build/win32/dirent/Makefile
build/win32/vs9/Makefile
glib/Makefile
+glib/glib.stp
glib/libcharset/Makefile
glib/gnulib/Makefile
glib/pcre/Makefile
diff --git a/docs/reference/glib/building.sgml b/docs/reference/glib/building.sgml
index a49a4d6d7..806349e8f 100644
--- a/docs/reference/glib/building.sgml
+++ b/docs/reference/glib/building.sgml
@@ -176,6 +176,19 @@ How to compile GLib itself
configure option.
+
+
+ The optional support for DTrace requires the sys/sdt.h header,
+ which is provided by SystemTap on Linux. To build GLib without DTrace, use the
+ configure option.
+
+
+
+
+ The optional support for SystemTap can be disabled with the
+ configure option.
+
+
@@ -238,6 +251,14 @@ How to compile GLib itself
--disable-selinux
--enable-selinux
+
+ --disable-dtrace
+ --enable-dtrace
+
+
+ --disable-systemtap
+ --enable-systemtap
+
--with-runtime-libdir=RELPATH
@@ -562,6 +583,27 @@ How to compile GLib itself
be included.
+
+
+ --disable-dtrace and
+ --enable-dtrace
+
+
+ By default the configure script will
+ detect if DTrace support is available, and use it.
+
+
+
+
+ --disable-systemtap and
+ --enable-systemtap
+
+
+ This option requires DTrace support. If it is available, then
+ the configure script will also check for
+ the presence of SystemTap.
+
+
--with-runtime-libdir=RELPATH
diff --git a/docs/reference/glib/running.sgml b/docs/reference/glib/running.sgml
index 9c33da800..ea10d153e 100644
--- a/docs/reference/glib/running.sgml
+++ b/docs/reference/glib/running.sgml
@@ -305,6 +305,19 @@ Which would print the contents of each widget in a list of widgets.
+
+SystemTap
+
+
+SystemTap is a dynamic whole-system
+analysis toolkit. GLib ships with a file glib.stp which defines a
+set of probe points, which you can hook into with custom SystemTap scripts.
+See the files glib.stp and gobject.stp which
+are in your shared SystemTap scripts directory.
+
+
+
+
Memory statistics
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 8882ae27d..7eac7ffb4 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -1,6 +1,8 @@
## Process this file with automake to produce Makefile.in
include $(top_srcdir)/Makefile.decl
+CLEANFILES=
+
if HAVE_GOOD_PRINTF
else
PRINTF_SUBDIR = gnulib
@@ -104,6 +106,7 @@ uninstall-ms-lib:
$(uninstall_ms_lib_cmd)
libglib_2_0_la_SOURCES = \
+ glib_probes.d \
garray.c \
gasyncqueue.c \
$(gatomic_c) \
@@ -130,6 +133,7 @@ libglib_2_0_la_SOURCES = \
giochannel.c \
gkeyfile.c \
glibintl.h \
+ glib_trace.h \
glist.c \
gmain.c \
gmappedfile.c \
@@ -325,6 +329,25 @@ libglib_2_0_la_LDFLAGS = \
INSTALL_PROGS=
+
+if ENABLE_DTRACE
+glib_probes.h: glib_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
+glib_probes.o: glib_probes.d Makefile
+ $(DTRACE) -G -s $< -o $@
+BUILT_SOURCES += glib_probes.h glib_probes.o
+CLEANFILES += glib_probes.h glib_probes.h.tmp
+libglib_2_0_la_LIBADD += glib_probes.o
+endif
+
+if ENABLE_SYSTEMTAP
+tapset_in_files = glib.stp.in
+tapsetdir = $(DESTDIR)@ABS_TAPSET_DIR@
+tapset_DATA = $(tapset_in_files:.stp.in=.stp)
+EXTRA_DIST += $(tapset_in_files)
+endif
+
gspawn-win32-helper-console.c:
echo '#define HELPER_CONSOLE' >$@
echo '#include "gspawn-win32-helper.c"' >>$@
diff --git a/glib/gdataset.c b/glib/gdataset.c
index 60adfe41e..57f6523e7 100644
--- a/glib/gdataset.c
+++ b/glib/gdataset.c
@@ -36,6 +36,7 @@
#include "glib.h"
#include "gdatasetprivate.h"
+#include "glib_trace.h"
#include "galias.h"
/**
@@ -1047,7 +1048,10 @@ g_quark_from_string_internal (const gchar *string,
quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
if (!quark)
- quark = g_quark_new (duplicate ? quark_strdup (string) : (gchar *)string);
+ {
+ quark = g_quark_new (duplicate ? quark_strdup (string) : (gchar *)string);
+ TRACE(GLIB_QUARK_NEW(string, quark));
+ }
return quark;
}
diff --git a/glib/glib.stp.in b/glib/glib.stp.in
new file mode 100644
index 000000000..95d33516a
--- /dev/null
+++ b/glib/glib.stp.in
@@ -0,0 +1,84 @@
+global gquarks
+
+/* This is needed to keep track of gquark for use in other probes.*/
+probe process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("quark__new")
+{
+ gquarks[pid(), $arg2] = user_string($arg1)
+}
+
+/**
+ * probe glib.quark_new - Called when a #GQuark is initially created
+ * @quark: integer value for the quark
+ * @str: string form of the quark
+ */
+probe glib.quark_new = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("quark__new")
+{
+ str = user_string ($arg1);
+ quark = $arg2;
+ probestr = sprintf("glib.quark_new(%s) -> %d", str, quark);
+}
+
+/**
+ * probe glib.mem_alloc - Called when a malloc block is initially requested
+ * @mem: Raw memory pointer returned
+ * @n_bytes: number of bytes
+ * @zeroed: Boolean value, %TRUE if this block was filled with NUL bytes
+ * @failable: Boolean value, %TRUE if program execution can continue on allocation failure
+ */
+probe glib.mem_alloc = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("mem__alloc")
+{
+ mem = $arg1;
+ n_bytes = $arg2;
+ zeroed = $arg3;
+ failable = $arg4;
+ probestr = sprintf("glib.mem_alloc(n_bytes=%d) -> %p", n_bytes, mem);
+}
+
+/**
+ * probe glib.mem_free - Called when a malloc block freed
+ */
+probe glib.mem_free = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("mem__free")
+{
+ mem = $arg1; /* ARG: @mem: Raw memory pointer */
+ probestr = sprintf("glib.mem_free(mem=%p)", mem);
+}
+
+/**
+ * probe glib.mem_realloc - Called when a malloc block is resized
+ * @mem: Raw memory pointer returned
+ * @old_mem: Original memory pointer
+ * @n_bytes: number of bytes
+ * @failable: Boolean value, %TRUE if program execution can continue on allocation failure
+ */
+probe glib.mem_realloc = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("mem__realloc")
+{
+ mem = $arg1;
+ old_mem = $arg2;
+ n_bytes = $arg3;
+ failable = $arg4;
+ probestr = sprintf("glib.mem_realloc(old_mem=%p, n_bytes=%d) -> %p", old_mem, n_bytes, mem);
+}
+
+/**
+ * probe glib.slice_alloc - Called when g_slice_alloc() is used
+ * @mem: Raw memory pointer returned
+ * @n_bytes: number of bytes
+ */
+probe glib.slice_alloc = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("slice__alloc")
+{
+ mem = $arg1;
+ n_bytes = $arg2;
+ probestr = sprintf("glib.slice_alloc(n_bytes=%d) -> %p", n_bytes, mem);
+}
+
+/**
+ * probe glib.slice_free - Called when memory slice is freed
+ * @mem: Raw memory pointer returned
+ * @n_bytes: Number of bytes
+ */
+probe glib.slice_free = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("slice__free")
+{
+ mem = $arg1;
+ n_bytes = $arg2;
+ probestr = sprintf("glib.slice_free(n_bytes=%d) -> %p", n_bytes, mem);
+}
diff --git a/glib/glib_probes.d b/glib/glib_probes.d
new file mode 100644
index 000000000..9232e1b65
--- /dev/null
+++ b/glib/glib_probes.d
@@ -0,0 +1,8 @@
+provider glib {
+ probe mem__alloc(void*, unsigned int, unsigned int, unsigned int);
+ probe mem__realloc(void*, void *, unsigned int, unsigned int);
+ probe mem__free(void*);
+ probe slice__alloc(void*, unsigned int);
+ probe slice__free(void*, unsigned int);
+ probe quark__new(char *, unsigned int);
+};
diff --git a/glib/glib_trace.h b/glib/glib_trace.h
new file mode 100644
index 000000000..789e88d69
--- /dev/null
+++ b/glib/glib_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
+ */
+
+#ifndef __GLIBTRACE_H__
+#define __GLIBTRACE_H__
+
+#ifndef SIZEOF_CHAR
+#error "config.h must be included prior to glib_trace.h"
+#endif
+
+#ifdef HAVE_DTRACE
+
+/* include the generated probes header and put markers in code */
+#include "glib_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 /* __GLIBTRACE_H__ */
diff --git a/glib/gmem.c b/glib/gmem.c
index b468deff9..f62e604c5 100644
--- a/glib/gmem.c
+++ b/glib/gmem.c
@@ -39,6 +39,7 @@
#include "gbacktrace.h"
#include "gtestutils.h"
#include "gthread.h"
+#include "glib_trace.h"
#include "galias.h"
@@ -121,7 +122,6 @@ static GMemVTable glib_mem_vtable = {
standard_try_realloc,
};
-
/* --- functions --- */
gpointer
g_malloc (gsize n_bytes)
@@ -133,6 +133,7 @@ g_malloc (gsize n_bytes)
gpointer mem;
mem = glib_mem_vtable.malloc (n_bytes);
+ TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 0, 0));
if (mem)
return mem;
@@ -140,6 +141,8 @@ g_malloc (gsize n_bytes)
G_STRLOC, n_bytes);
}
+ TRACE(GLIB_MEM_ALLOC((void*) NULL, (int) n_bytes, 0, 0));
+
return NULL;
}
@@ -153,6 +156,7 @@ g_malloc0 (gsize n_bytes)
gpointer mem;
mem = glib_mem_vtable.calloc (1, n_bytes);
+ TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 1, 0));
if (mem)
return mem;
@@ -160,6 +164,8 @@ g_malloc0 (gsize n_bytes)
G_STRLOC, n_bytes);
}
+ TRACE(GLIB_MEM_ALLOC((void*) NULL, (int) n_bytes, 1, 0));
+
return NULL;
}
@@ -167,13 +173,16 @@ gpointer
g_realloc (gpointer mem,
gsize n_bytes)
{
+ gpointer newmem;
+
if (G_UNLIKELY (!g_mem_initialized))
g_mem_init_nomessage();
if (G_LIKELY (n_bytes))
{
- mem = glib_mem_vtable.realloc (mem, n_bytes);
- if (mem)
- return mem;
+ newmem = glib_mem_vtable.realloc (mem, n_bytes);
+ TRACE (GLIB_MEM_REALLOC((void*) newmem, (void*)mem, (unsigned int) n_bytes, 0));
+ if (newmem)
+ return newmem;
g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
G_STRLOC, n_bytes);
@@ -182,6 +191,8 @@ g_realloc (gpointer mem,
if (mem)
glib_mem_vtable.free (mem);
+ TRACE (GLIB_MEM_REALLOC((void*) NULL, (void*)mem, 0, 0));
+
return NULL;
}
@@ -192,17 +203,24 @@ g_free (gpointer mem)
g_mem_init_nomessage();
if (G_LIKELY (mem))
glib_mem_vtable.free (mem);
+ TRACE(GLIB_MEM_FREE((void*) mem));
}
gpointer
g_try_malloc (gsize n_bytes)
{
+ gpointer mem;
+
if (G_UNLIKELY (!g_mem_initialized))
g_mem_init_nomessage();
if (G_LIKELY (n_bytes))
- return glib_mem_vtable.try_malloc (n_bytes);
+ mem = glib_mem_vtable.try_malloc (n_bytes);
else
- return NULL;
+ mem = NULL;
+
+ TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 0, 1));
+
+ return mem;
}
gpointer
@@ -210,7 +228,12 @@ g_try_malloc0 (gsize n_bytes)
{
gpointer mem;
- mem = g_try_malloc (n_bytes);
+ if (G_UNLIKELY (!g_mem_initialized))
+ g_mem_init_nomessage();
+ if (G_LIKELY (n_bytes))
+ mem = glib_mem_vtable.try_malloc (n_bytes);
+ else
+ mem = NULL;
if (mem)
memset (mem, 0, n_bytes);
@@ -222,15 +245,22 @@ gpointer
g_try_realloc (gpointer mem,
gsize n_bytes)
{
+ gpointer newmem;
+
if (G_UNLIKELY (!g_mem_initialized))
g_mem_init_nomessage();
if (G_LIKELY (n_bytes))
- return glib_mem_vtable.try_realloc (mem, n_bytes);
+ newmem = glib_mem_vtable.try_realloc (mem, n_bytes);
+ else
+ {
+ newmem = NULL;
+ if (mem)
+ glib_mem_vtable.free (mem);
+ }
- if (mem)
- glib_mem_vtable.free (mem);
+ TRACE (GLIB_MEM_REALLOC((void*) newmem, (void*)mem, (unsigned int) n_bytes, 1));
- return NULL;
+ return newmem;
}
diff --git a/glib/gslice.c b/glib/gslice.c
index 66fd9e5fa..41bd93cda 100644
--- a/glib/gslice.c
+++ b/glib/gslice.c
@@ -35,6 +35,7 @@
#include "gmem.h" /* gslice.h */
#include "gthreadprivate.h"
#include "glib.h"
+#include "glib_trace.h"
#include "galias.h"
#ifdef HAVE_UNISTD_H
#include /* sysconf() */
@@ -836,6 +837,9 @@ g_slice_alloc (gsize mem_size)
mem = g_malloc (mem_size);
if (G_UNLIKELY (allocator->config.debug_blocks))
smc_notify_alloc (mem, mem_size);
+
+ TRACE (GLIB_SLICE_ALLOC((void*)mem, mem_size));
+
return mem;
}
@@ -897,6 +901,7 @@ g_slice_free1 (gsize mem_size,
memset (mem_block, 0, mem_size);
g_free (mem_block);
}
+ TRACE (GLIB_SLICE_FREE((void*)mem_block, mem_size));
}
void