Commit 4addb112 authored by Daniel P. Berrangé's avatar Daniel P. Berrangé Committed by Anthony Liguori
Browse files

Add a DTrace tracing backend targetted for SystemTAP compatability



This introduces a new tracing backend that targets the SystemTAP
implementation of DTrace userspace tracing. The core functionality
should be applicable and standard across any DTrace implementation
on Solaris, OS-X, *BSD, but the Makefile rules will likely need
some small additional changes to cope with OS specific build
requirements.

This backend builds a little differently from the other tracing
backends. Specifically there is no 'trace.c' file, because the
'dtrace' command line tool generates a '.o' file directly from
the dtrace probe definition file. The probe definition is usually
named with a '.d' extension but QEMU uses '.d' files for its
external makefile dependancy tracking, so this uses '.dtrace' as
the extension for the probe definition file.

The 'tracetool' program gains the ability to generate a trace.h
file for DTrace, and also to generate the trace.d file containing
the dtrace probe definition.

Example usage of a dtrace probe in systemtap looks like:

  probe process("qemu").mark("qemu_malloc") {
    printf("Malloc %d %p\n", $arg1, $arg2);
  }

* .gitignore: Ignore trace-dtrace.*
* Makefile: Extra rules for generating DTrace files
* Makefile.obj: Don't build trace.o for DTrace, use
  trace-dtrace.o generated by 'dtrace' instead
* tracetool: Support for generating DTrace data files

Signed-off-by: default avatarDaniel P. Berrange <berrange@redhat.com>
Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parent 96968466
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@ config-host.*
config-target.*
trace.h
trace.c
trace-dtrace.h
trace-dtrace.dtrace
*-timestamp
*-softmmu
*-darwin-user
+23 −0
Original line number Diff line number Diff line
# Makefile for QEMU.

GENERATED_HEADERS = config-host.h trace.h qemu-options.def
ifeq ($(TRACE_BACKEND),dtrace)
GENERATED_HEADERS += trace-dtrace.h
endif

ifneq ($(wildcard config-host.mak),)
# Put the all: rule here so that config-host.mak can contain dependencies.
@@ -108,7 +111,11 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)

bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)

ifeq ($(TRACE_BACKEND),dtrace)
trace.h: trace.h-timestamp trace-dtrace.h
else
trace.h: trace.h-timestamp
endif
trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
	$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
	@cmp -s $@ trace.h || cp $@ trace.h
@@ -120,6 +127,20 @@ trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak

trace.o: trace.c $(GENERATED_HEADERS)

trace-dtrace.h: trace-dtrace.dtrace
	$(call quiet-command,dtrace -o $@ -h -s $<, "  GEN   trace-dtrace.h")

# Normal practice is to name DTrace probe file with a '.d' extension
# but that gets picked up by QEMU's Makefile as an external dependancy
# rule file. So we use '.dtrace' instead
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
	$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
	@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace

trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
	$(call quiet-command,dtrace -o $@ -G -s $<, "  GEN trace-dtrace.o")

simpletrace.o: simpletrace.c $(GENERATED_HEADERS)

version.o: $(SRC_PATH)/version.rc config-host.mak
@@ -157,6 +178,8 @@ clean:
	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
	rm -f qemu-img-cmds.h
	rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
	rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
	rm -f trace-dtrace.h trace-dtrace.h-timestamp
	$(MAKE) -C tests clean
	for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
	if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
+4 −0
Original line number Diff line number Diff line
@@ -286,11 +286,15 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
######################################################################
# trace

ifeq ($(TRACE_BACKEND),dtrace)
trace-obj-y = trace-dtrace.o
else
trace-obj-y = trace.o
ifeq ($(TRACE_BACKEND),simple)
trace-obj-y += simpletrace.o
user-obj-y += qemu-timer-common.o
endif
endif

vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)

+13 −1
Original line number Diff line number Diff line
@@ -929,7 +929,7 @@ echo " --enable-docs enable documentation build"
echo "  --disable-docs           disable documentation build"
echo "  --disable-vhost-net      disable vhost-net acceleration support"
echo "  --enable-vhost-net       enable vhost-net acceleration support"
echo "  --trace-backend=B        Trace backend nop simple ust"
echo "  --trace-backend=B        Trace backend nop simple ust dtrace"
echo "  --trace-file=NAME        Full PATH,NAME of file to store traces"
echo "                           Default:trace-<pid>"
echo "  --disable-spice          disable spice"
@@ -2193,6 +2193,18 @@ EOF
    exit 1
  fi
fi

##########################################
# For 'dtrace' backend, test if 'dtrace' command is present
if test "$trace_backend" = "dtrace"; then
  if ! has 'dtrace' ; then
    echo
    echo "Error: dtrace command is not found in PATH $PATH"
    echo
    exit 1
  fi
fi

##########################################
# End of CC checks
# After here, no more $cc or $ld runs
+106 −10
Original line number Diff line number Diff line
@@ -20,10 +20,12 @@ Backends:
  --nop     Tracing disabled
  --simple  Simple built-in backend
  --ust     LTTng User Space Tracing backend
  --dtrace  DTrace/SystemTAP backend

Output formats:
  -h    Generate .h file
  -c    Generate .c file
  -d    Generate .d file (DTrace only)
EOF
    exit 1
}
@@ -46,8 +48,9 @@ get_args()
# Get the argument name list of a trace event
get_argnames()
{
    local nfields field name
    local nfields field name sep
    nfields=0
    sep="$2"
    for field in $(get_args "$1"); do
        nfields=$((nfields + 1))

@@ -58,7 +61,7 @@ get_argnames()
        name=${field%,}
        test "$field" = "$name" && continue

        printf "%s" "$name, "
        printf "%s%s " $name $sep
    done

    # Last argument name
@@ -73,7 +76,7 @@ get_argc()
{
    local name argc
    argc=0
    for name in $(get_argnames "$1"); do
    for name in $(get_argnames "$1", ","); do
        argc=$((argc + 1))
    done
    echo $argc
@@ -154,7 +157,7 @@ EOF
cast_args_to_uint64_t()
{
    local arg
    for arg in $(get_argnames "$1"); do
    for arg in $(get_argnames "$1", ","); do
        printf "%s" "(uint64_t)(uintptr_t)$arg"
    done
}
@@ -247,7 +250,7 @@ linetoh_ust()
    local name args argnames
    name=$(get_name "$1")
    args=$(get_args "$1")
    argnames=$(get_argnames "$1")
    argnames=$(get_argnames "$1", ",")

    cat <<EOF
DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
@@ -274,7 +277,7 @@ linetoc_ust()
    local name args argnames fmt
    name=$(get_name "$1")
    args=$(get_args "$1")
    argnames=$(get_argnames "$1")
    argnames=$(get_argnames "$1", ",")
    fmt=$(get_fmt "$1")

    cat <<EOF
@@ -306,6 +309,87 @@ EOF
    echo "}"
}

linetoh_begin_dtrace()
{
    cat <<EOF
#include "trace-dtrace.h"
EOF
}

linetoh_dtrace()
{
    local name args argnames state nameupper
    name=$(get_name "$1")
    args=$(get_args "$1")
    argnames=$(get_argnames "$1", ",")
    state=$(get_state "$1")
    if [ "$state" = "0" ] ; then
        name=${name##disable }
    fi

    nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`

    # Define an empty function for the trace event
    cat <<EOF
static inline void trace_$name($args) {
    if (QEMU_${nameupper}_ENABLED()) {
        QEMU_${nameupper}($argnames);
    }
}
EOF
}

linetoh_end_dtrace()
{
    return
}

linetoc_begin_dtrace()
{
    return
}

linetoc_dtrace()
{
    # No need for function definitions in dtrace backend
    return
}

linetoc_end_dtrace()
{
    return
}

linetod_begin_dtrace()
{
    cat <<EOF
provider qemu {
EOF
}

linetod_dtrace()
{
    local name args state
    name=$(get_name "$1")
    args=$(get_args "$1")
    state=$(get_state "$1")
    if [ "$state" = "0" ] ; then
        name=${name##disable }
    fi

    # Define prototype for probe arguments
    cat <<EOF
        probe $name($args);
EOF
}

linetod_end_dtrace()
{
    cat <<EOF
};
EOF
}

# Process stdin by calling begin, line, and end functions for the backend
convert()
{
@@ -324,9 +408,10 @@ convert()
        disable=${str%%disable *}
        echo
        if test -z "$disable"; then
            # Pass the disabled state as an arg to lineto$1_simple().
            # For all other cases, call lineto$1_nop()
            if [ $backend = "simple" ]; then
            # Pass the disabled state as an arg for the simple
            # or DTrace backends which handle it dynamically.
            # For all other backends, call lineto$1_nop()
            if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
                "$process_line" "$str"
            else
                "lineto$1_nop" "${str##disable }"
@@ -360,9 +445,19 @@ tracetoc()
    convert c
}

tracetod()
{
    if [ $backend != "dtrace" ]; then
       echo "DTrace probe generator not applicable to $backend backend"
       exit 1
    fi
    echo "/* This file is autogenerated by tracetool, do not edit. */"
    convert d
}

# Choose backend
case "$1" in
"--nop" | "--simple" | "--ust") backend="${1#--}" ;;
"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
*) usage ;;
esac
shift
@@ -370,6 +465,7 @@ shift
case "$1" in
"-h") tracetoh ;;
"-c") tracetoc ;;
"-d") tracetod ;;
"--check-backend") exit 0 ;; # used by ./configure to test for backend
*) usage ;;
esac