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

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>
This commit is contained in:
Daniel P. Berrange 2010-11-12 13:20:24 +00:00 committed by Anthony Liguori
parent 06da6e44d7
commit b3d08c029d
5 changed files with 154 additions and 11 deletions

2
.gitignore vendored
View file

@ -4,6 +4,8 @@ config-host.*
config-target.*
trace.h
trace.c
trace-dtrace.h
trace-dtrace.dtrace
*-timestamp
*-softmmu
*-darwin-user

View file

@ -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.
@ -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; \

View file

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

14
configure vendored
View file

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

122
tracetool
View file

@ -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,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()
{
@ -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 }"
@ -360,9 +451,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 +471,7 @@ shift
case "$1" in
"-h") tracetoh ;;
"-c") tracetoc ;;
"-d") tracetod ;;
"--check-backend") exit 0 ;; # used by ./configure to test for backend
*) usage ;;
esac