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. + + + <systemitem>--disable-dtrace</systemitem> and + <systemitem>--enable-dtrace</systemitem> + + + By default the configure script will + detect if DTrace support is available, and use it. + + + + + <systemitem>--disable-systemtap</systemitem> and + <systemitem>--enable-systemtap</systemitem> + + + This option requires DTrace support. If it is available, then + the configure script will also check for + the presence of SystemTap. + + <systemitem>--with-runtime-libdir=RELPATH</systemitem> 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