From c155330f04f933d13298d5cddab6b7f3dc9d218f Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 10 Oct 2011 13:26:15 +0100 Subject: [PATCH] Add systemtap/DTrace probes. Mainly this is a documentation change. However a sample of DTrace-compatible userspace probes are also added. --- README | 3 +++ configure.ac | 5 ++++ src/guestfs-internal.h | 20 ++++++++++++++ src/guestfs.pod | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/launch.c | 10 +++++++ 5 files changed, 110 insertions(+) diff --git a/README b/README index 6b2078e..396c8bb 100644 --- a/README +++ b/README @@ -77,6 +77,9 @@ For basic functionality and the C tools: - Berkeley DB 'db_dump' and 'db_load' utilities (db4-utils or db4.X-util or similar) (optional) +- systemtap/DTrace userspace probes (optional) + http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps + - perldoc (pod2man, pod2text, pod2html) to generate the manual pages and other documentation. diff --git a/configure.ac b/configure.ac index 2bd98c6..e0fd7de 100644 --- a/configure.ac +++ b/configure.ac @@ -346,6 +346,11 @@ if test "x$have_libselinux" = "xyes"; then fi AC_SUBST([SELINUX_LIB]) +dnl Check for systemtap/DTrace userspace probes (optional). +dnl http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps +AC_CHECK_HEADERS([sys/sdt.h]) +dnl AC_CHECK_PROG([DTRACE],[dtrace],[dtrace],[no]) + dnl Check for cpio which isn't in the default Pardus install amazingly. AC_CHECK_PROG([CPIO],[cpio],[cpio],[no]) test "x$CPIO" = "xno" && diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 494003e..64cf696 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -43,6 +43,26 @@ #define N_(str) str #endif +#ifdef HAVE_SYS_SDT_H +#include +/* NB: The 'name' parameter is a literal identifier, NOT a string! */ +#define TRACE0(name) DTRACE_PROBE(guestfs, name) +#define TRACE1(name, arg1) \ + DTRACE_PROBE(guestfs, name, (arg1)) +#define TRACE2(name, arg1, arg2) \ + DTRACE_PROBE(guestfs, name, (arg1), (arg2)) +#define TRACE3(name, arg1, arg2, arg3) \ + DTRACE_PROBE(guestfs, name, (arg1), (arg2), (arg3)) +#define TRACE4(name, arg1, arg2, arg3, arg4) \ + DTRACE_PROBE(guestfs, name, (arg1), (arg2), (arg3), (arg4)) +#else +#define TRACE0(name) +#define TRACE1(name, arg1) +#define TRACE2(name, arg1, arg2) +#define TRACE3(name, arg1, arg2, arg3) +#define TRACE4(name, arg1, arg2, arg3, arg4) +#endif + #define TMP_TEMPLATE_ON_STACK(var) \ const char *ttos_tmpdir = guestfs_tmpdir (); \ char var[strlen (ttos_tmpdir) + 32]; \ diff --git a/src/guestfs.pod b/src/guestfs.pod index 1a5abc6..ada9f1e 100644 --- a/src/guestfs.pod +++ b/src/guestfs.pod @@ -2165,6 +2165,77 @@ are being deleted, but other manipulations of keys within the loop might not terminate unless you also maintain an indication of which keys have been visited. +=head1 SYSTEMTAP + +The libguestfs C library can be probed using systemtap or DTrace. +This is true of any library, not just libguestfs. However libguestfs +also contains static markers to help in probing internal operations. + +You can list all the static markers by doing: + + stap -l 'process("/usr/lib*/libguestfs.so.0") + .provider("guestfs").mark("*")' + +B These static markers are I part of the stable API and +may change in future versions. + +=head2 SYSTEMTAP SCRIPT EXAMPLE + +This script contains examples of displaying both the static markers +and some ordinary C entry points: + + global last; + + function display_time () { + now = gettimeofday_us (); + delta = 0; + if (last > 0) + delta = now - last; + last = now; + + printf ("%d (+%d):", now, delta); + } + + probe begin { + last = 0; + printf ("ready\n"); + } + + /* Display all calls to static markers. */ + probe process("/usr/lib*/libguestfs.so.0") + .provider("guestfs").mark("*") ? { + display_time(); + printf ("\t%s %s\n", $$name, $$parms); + } + + /* Display all calls to guestfs_mkfs* functions. */ + probe process("/usr/lib*/libguestfs.so.0") + .function("guestfs_mkfs*") ? { + display_time(); + printf ("\t%s %s\n", probefunc(), $$parms); + } + +The script above can be saved to C and run using the +L program. Note that you either have to be root, or you have +to add yourself to several special stap groups. Consult the systemtap +documentation for more information. + + # stap /tmp/test.stap + ready + +In another terminal, run a guestfish command such as this: + + guestfish -N fs + +In the first terminal, stap trace output similar to this is shown: + + 1318248056692655 (+0): launch_start + 1318248056692850 (+195): launch_build_appliance_start + 1318248056818285 (+125435): launch_build_appliance_end + 1318248056838059 (+19774): launch_run_qemu + 1318248061071167 (+4233108): launch_end + 1318248061280324 (+209157): guestfs_mkfs g=0x1024ab0 fstype=0x46116f device=0x1024e60 + =begin html @@ -3216,6 +3287,7 @@ L, L, L, L, +L, L. Tools with a similar purpose: diff --git a/src/launch.c b/src/launch.c index b0f5b39..8e171f7 100644 --- a/src/launch.c +++ b/src/launch.c @@ -389,6 +389,8 @@ guestfs__launch (guestfs_h *g) return -1; } + TRACE0 (launch_start); + /* Make the temporary directory. */ if (!g->tmpdir) { TMP_TEMPLATE_ON_STACK (dir_template); @@ -439,11 +441,15 @@ launch_appliance (guestfs_h *g) gettimeofday (&g->launch_t, NULL); guestfs___launch_send_progress (g, 0); + TRACE0 (launch_build_appliance_start); + /* Locate and/or build the appliance. */ char *kernel = NULL, *initrd = NULL, *appliance = NULL; if (guestfs___build_appliance (g, &kernel, &initrd, &appliance) == -1) return -1; + TRACE0 (launch_build_appliance_end); + guestfs___launch_send_progress (g, 3); if (g->verbose) @@ -696,6 +702,8 @@ launch_appliance (guestfs_h *g) setenv ("LC_ALL", "C", 1); + TRACE0 (launch_run_qemu); + execv (g->qemu, g->cmdline); /* Run qemu. */ perror (g->qemu); _exit (EXIT_FAILURE); @@ -825,6 +833,8 @@ launch_appliance (guestfs_h *g) goto cleanup1; } + TRACE0 (launch_end); + guestfs___launch_send_progress (g, 12); return 0; -- 1.8.3.1