Initial support for dtrace and systemtap

This adds static markers for dtrace, which are also usable
by systemtap. Additionally it adds a tapset for systemtap
that makes it easier to use the static markers.

These are enabled by default.

This initial set of probes is rather limited:

* allocation and free using g_malloc & co
* allocation and free using g_slice
* gquark name tracking (useful for converting quarks to strings in probes)

Notes on naming:

Its traditional with dtrace to use probe names with dashes as
delimiter (slice-alloc). Since dashes are not usable in identifiers
the C code uses double underscores (slice__alloc) which is converted
to dashes in the UI. We follow this for the shared lowlevel probe
names.

Additionally dtrace supports putting a "provider" part in the probe
names which is essentially a namespacing thing. On systemtap this
field is currently ignored (but may be implemented in the future), but
this is not really a problem since in systemtap the probes are
specified by combining the solib file and the marker name, so there
can't really be name conflicts.

For the systemtap tapset highlevel probes we instead use names that
are systemtapish with single dashes as separators.

https://bugzilla.gnome.org/show_bug.cgi?id=606044
This commit is contained in:
Alexander Larsson 2009-12-18 21:25:47 +01:00 committed by Colin Walters
parent c3bc0f4f8f
commit bef9efd0a9
10 changed files with 317 additions and 12 deletions

View File

@ -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

View File

@ -176,6 +176,19 @@ How to compile GLib itself
<option>--disable-selinux</option> configure option.
</para>
</listitem>
<listitem>
<para>
The optional support for DTrace requires the <filename>sys/sdt.h</filename> header,
which is provided by SystemTap on Linux. To build GLib without DTrace, use the
<option>--disable-dtrace</option> configure option.
</para>
</listitem>
<listitem>
<para>
The optional support for <ulink url="http://sourceware.org/systemtap/">SystemTap</ulink> can be disabled with the
<option>--disable-systemtap</option> configure option.
</para>
</listitem>
</itemizedlist>
</refsect1>
@ -238,6 +251,14 @@ How to compile GLib itself
<arg>--disable-selinux</arg>
<arg>--enable-selinux</arg>
</group>
<group>
<arg>--disable-dtrace</arg>
<arg>--enable-dtrace</arg>
</group>
<group>
<arg>--disable-systemtap</arg>
<arg>--enable-systemtap</arg>
</group>
<group>
<arg>--with-runtime-libdir=RELPATH</arg>
</group>
@ -562,6 +583,27 @@ How to compile GLib itself
be included.
</para>
</formalpara>
<formalpara>
<title><systemitem>--disable-dtrace</systemitem> and
<systemitem>--enable-dtrace</systemitem></title>
<para>
By default the <command>configure</command> script will
detect if DTrace support is available, and use it.
</para>
</formalpara>
<formalpara>
<title><systemitem>--disable-systemtap</systemitem> and
<systemitem>--enable-systemtap</systemitem></title>
<para>
This option requires DTrace support. If it is available, then
the <command>configure</command> script will also check for
the presence of SystemTap.
</para>
</formalpara>
<formalpara>
<title><systemitem>--with-runtime-libdir=RELPATH</systemitem></title>

View File

@ -305,6 +305,19 @@ Which would print the contents of each widget in a list of widgets.
</refsect2>
<refsect2>
<title>SystemTap</title>
<para>
<ulink url="http://sourceware.org/systemtap/">SystemTap</ulink> is a dynamic whole-system
analysis toolkit. GLib ships with a file <filename>glib.stp</filename> which defines a
set of probe points, which you can hook into with custom SystemTap scripts.
See the files <filename>glib.stp</filename> and <filename>gobject.stp</filename> which
are in your shared SystemTap scripts directory.
</para>
</refsect2>
<refsect2>
<title>Memory statistics</title>

View File

@ -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"' >>$@

View File

@ -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;
}

84
glib/glib.stp.in Normal file
View File

@ -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);
}

8
glib/glib_probes.d Normal file
View File

@ -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);
};

43
glib/glib_trace.h Normal file
View File

@ -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 __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__ */

View File

@ -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;
}

View File

@ -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 <unistd.h> /* 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