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.* config-target.*
trace.h trace.h
trace.c trace.c
trace-dtrace.h
trace-dtrace.dtrace
*-timestamp *-timestamp
*-softmmu *-softmmu
*-darwin-user *-darwin-user

View File

@ -1,6 +1,9 @@
# Makefile for QEMU. # Makefile for QEMU.
GENERATED_HEADERS = config-host.h trace.h qemu-options.def 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),) ifneq ($(wildcard config-host.mak),)
# Put the all: rule here so that config-host.mak can contain dependencies. # 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) 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 trace.h: trace.h-timestamp
endif
trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h") $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ 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.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) simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
version.o: $(SRC_PATH)/version.rc config-host.mak 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 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 qemu-img-cmds.h
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp 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 $(MAKE) -C tests clean
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \ for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ 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 # trace
ifeq ($(TRACE_BACKEND),dtrace)
trace-obj-y = trace-dtrace.o
else
trace-obj-y = trace.o trace-obj-y = trace.o
ifeq ($(TRACE_BACKEND),simple) ifeq ($(TRACE_BACKEND),simple)
trace-obj-y += simpletrace.o trace-obj-y += simpletrace.o
user-obj-y += qemu-timer-common.o user-obj-y += qemu-timer-common.o
endif endif
endif
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) 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-docs disable documentation build"
echo " --disable-vhost-net disable vhost-net acceleration support" echo " --disable-vhost-net disable vhost-net acceleration support"
echo " --enable-vhost-net enable 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 " --trace-file=NAME Full PATH,NAME of file to store traces"
echo " Default:trace-<pid>" echo " Default:trace-<pid>"
echo " --disable-spice disable spice" echo " --disable-spice disable spice"
@ -2193,6 +2193,18 @@ EOF
exit 1 exit 1
fi fi
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 # End of CC checks
# After here, no more $cc or $ld runs # After here, no more $cc or $ld runs

122
tracetool
View File

@ -20,10 +20,12 @@ Backends:
--nop Tracing disabled --nop Tracing disabled
--simple Simple built-in backend --simple Simple built-in backend
--ust LTTng User Space Tracing backend --ust LTTng User Space Tracing backend
--dtrace DTrace/SystemTAP backend
Output formats: Output formats:
-h Generate .h file -h Generate .h file
-c Generate .c file -c Generate .c file
-d Generate .d file (DTrace only)
EOF EOF
exit 1 exit 1
} }
@ -46,8 +48,9 @@ get_args()
# Get the argument name list of a trace event # Get the argument name list of a trace event
get_argnames() get_argnames()
{ {
local nfields field name local nfields field name sep
nfields=0 nfields=0
sep="$2"
for field in $(get_args "$1"); do for field in $(get_args "$1"); do
nfields=$((nfields + 1)) nfields=$((nfields + 1))
@ -58,7 +61,7 @@ get_argnames()
name=${field%,} name=${field%,}
test "$field" = "$name" && continue test "$field" = "$name" && continue
printf "%s" "$name, " printf "%s%s " $name $sep
done done
# Last argument name # Last argument name
@ -73,7 +76,7 @@ get_argc()
{ {
local name argc local name argc
argc=0 argc=0
for name in $(get_argnames "$1"); do for name in $(get_argnames "$1", ","); do
argc=$((argc + 1)) argc=$((argc + 1))
done done
echo $argc echo $argc
@ -154,7 +157,7 @@ EOF
cast_args_to_uint64_t() cast_args_to_uint64_t()
{ {
local arg local arg
for arg in $(get_argnames "$1"); do for arg in $(get_argnames "$1", ","); do
printf "%s" "(uint64_t)(uintptr_t)$arg" printf "%s" "(uint64_t)(uintptr_t)$arg"
done done
} }
@ -247,7 +250,7 @@ linetoh_ust()
local name args argnames local name args argnames
name=$(get_name "$1") name=$(get_name "$1")
args=$(get_args "$1") args=$(get_args "$1")
argnames=$(get_argnames "$1") argnames=$(get_argnames "$1", ",")
cat <<EOF cat <<EOF
DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames)); DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
@ -274,7 +277,7 @@ linetoc_ust()
local name args argnames fmt local name args argnames fmt
name=$(get_name "$1") name=$(get_name "$1")
args=$(get_args "$1") args=$(get_args "$1")
argnames=$(get_argnames "$1") argnames=$(get_argnames "$1", ",")
fmt=$(get_fmt "$1") fmt=$(get_fmt "$1")
cat <<EOF cat <<EOF
@ -306,6 +309,93 @@ EOF
echo "}" 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 # Process stdin by calling begin, line, and end functions for the backend
convert() convert()
{ {
@ -324,9 +414,10 @@ convert()
disable=${str%%disable *} disable=${str%%disable *}
echo echo
if test -z "$disable"; then if test -z "$disable"; then
# Pass the disabled state as an arg to lineto$1_simple(). # Pass the disabled state as an arg for the simple
# For all other cases, call lineto$1_nop() # or DTrace backends which handle it dynamically.
if [ $backend = "simple" ]; then # For all other backends, call lineto$1_nop()
if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
"$process_line" "$str" "$process_line" "$str"
else else
"lineto$1_nop" "${str##disable }" "lineto$1_nop" "${str##disable }"
@ -360,9 +451,19 @@ tracetoc()
convert c 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 # Choose backend
case "$1" in case "$1" in
"--nop" | "--simple" | "--ust") backend="${1#--}" ;; "--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
*) usage ;; *) usage ;;
esac esac
shift shift
@ -370,6 +471,7 @@ shift
case "$1" in case "$1" in
"-h") tracetoh ;; "-h") tracetoh ;;
"-c") tracetoc ;; "-c") tracetoc ;;
"-d") tracetod ;;
"--check-backend") exit 0 ;; # used by ./configure to test for backend "--check-backend") exit 0 ;; # used by ./configure to test for backend
*) usage ;; *) usage ;;
esac esac