Skip to content

Commit

Permalink
Add a DTrace tracing backend targetted for SystemTAP compatability
Browse files Browse the repository at this point in the history
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

Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
  • Loading branch information
berrange authored and Anthony Liguori committed Nov 21, 2010
1 parent 06da6e4 commit b3d08c0
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 11 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -4,6 +4,8 @@ config-host.*
config-target.*
trace.h
trace.c
trace-dtrace.h
trace-dtrace.dtrace
*-timestamp
*-softmmu
*-darwin-user
Expand Down
23 changes: 23 additions & 0 deletions Makefile
@@ -1,6 +1,9 @@
# 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.
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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; \
Expand Down
4 changes: 4 additions & 0 deletions Makefile.objs
Expand Up @@ -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)

Expand Down
14 changes: 13 additions & 1 deletion configure
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
122 changes: 112 additions & 10 deletions tracetool
Expand Up @@ -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
}
Expand All @@ -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))

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

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

# Last argument name
Expand All @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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));
Expand All @@ -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
Expand Down Expand Up @@ -306,6 +309,93 @@ 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

# DTrace provider syntax expects foo() for empty
# params, not foo(void)
if [ "$args" = "void" ]; then
args=""
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()
{
Expand All @@ -324,9 +414,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 }"
Expand Down Expand Up @@ -360,16 +451,27 @@ 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

case "$1" in
"-h") tracetoh ;;
"-c") tracetoc ;;
"-d") tracetod ;;
"--check-backend") exit 0 ;; # used by ./configure to test for backend
*) usage ;;
esac
Expand Down

0 comments on commit b3d08c0

Please sign in to comment.