diff mbox

[01/14] trace: Add trace-events file for declaring trace events

Message ID 1283786051-29530-2-git-send-email-stefanha@linux.vnet.ibm.com
State New
Headers show

Commit Message

Stefan Hajnoczi Sept. 6, 2010, 3:13 p.m. UTC
This patch introduces the trace-events file where trace events can be
declared like so:

qemu_malloc(size_t size) "size %zu"
qemu_free(void *ptr) "ptr %p"

These trace event declarations are processed by a new tool called
tracetool to generate code for the trace events.  Trace event
declarations are independent of the backend tracing system (LTTng User
Space Tracing, ftrace markers, DTrace).

The default "nop" backend generates empty trace event functions.
Therefore trace events are disabled by default.

The trace-events file serves two purposes:

1. Adding trace events is easy.  It is not necessary to understand the
   details of a backend tracing system.  The trace-events file is a
   single location where trace events can be declared without code
   duplication.

2. QEMU is not tightly coupled to one particular backend tracing system.
   In order to support tracing across QEMU host platforms and to
   anticipate new backend tracing systems that are currently maturing,
   it is important to be flexible and not tied to one system.

This commit includes fixes from Prerna Saxena
<prerna@linux.vnet.ibm.com> and Blue Swirl <blauwirbel@gmail.com>.

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
---
 .gitignore      |    2 +
 Makefile        |   17 ++++-
 Makefile.objs   |    5 ++
 Makefile.target |    1 +
 configure       |   18 ++++++
 trace-events    |   24 ++++++++
 tracetool       |  175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 238 insertions(+), 4 deletions(-)
 create mode 100644 trace-events
 create mode 100755 tracetool

Comments

Andreas Färber Sept. 11, 2010, 9:53 p.m. UTC | #1
Hello Stefan,

Am 06.09.2010 um 17:13 schrieb Stefan Hajnoczi:

> diff --git a/Makefile b/Makefile
> index f95cc2f..3c5e6a0 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1,6 +1,6 @@
> # Makefile for QEMU.
>
> -GENERATED_HEADERS = config-host.h
> +GENERATED_HEADERS = config-host.h trace.h
>
> ifneq ($(wildcard config-host.mak),)
> # Put the all: rule here so that config-host.mak can contain  
> dependencies.
> @@ -104,16 +104,24 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>
> bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
>
> +trace.h: $(SRC_PATH)/trace-events config-host.mak
> +	$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) - 
> h < $< > $@,"  GEN   $@")
> +
> +trace.c: $(SRC_PATH)/trace-events config-host.mak
> +	$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) - 
> c < $< > $@,"  GEN   $@")
> +
> +trace.o: trace.c $(GENERATED_HEADERS)

There's a dependency issue hidden here: The user emulators recurse  
into *-user with just a dependency on trace.h. The build then fails  
because the target Makefile does not know how to build ../trace.o  
since the rule is in this Makefile instead.

I noticed it with ppc-haiku-user but this should be visible with linux- 
user on a clean build, too.

Adding trace.o or $(trace-obj-y) somewhere before subdir-libuser seems  
to help. I'll post a patch later on if no one beats me.

Andreas

> +
> ######################################################################
>
> qemu-img.o: qemu-img-cmds.h
> qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS)
>
> -qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(block-obj- 
> y) $(qobject-obj-y)
> +qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(trace-obj- 
> y) $(block-obj-y) $(qobject-obj-y)
>
> -qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(block-obj- 
> y) $(qobject-obj-y)
> +qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(trace-obj- 
> y) $(block-obj-y) $(qobject-obj-y)
>
> -qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(block- 
> obj-y) $(qobject-obj-y)
> +qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(trace- 
> obj-y) $(block-obj-y) $(qobject-obj-y)
>
> qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
> 	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
> @@ -133,6 +141,7 @@ clean:
> 	rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
> 	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
> 	$(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; \
Stefan Hajnoczi Sept. 12, 2010, 5:16 p.m. UTC | #2
On Sat, Sep 11, 2010 at 10:53 PM, Andreas Färber <andreas.faerber@web.de> wrote:
> Am 06.09.2010 um 17:13 schrieb Stefan Hajnoczi:
>
>> diff --git a/Makefile b/Makefile
>> index f95cc2f..3c5e6a0 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -1,6 +1,6 @@
>> # Makefile for QEMU.
>>
>> -GENERATED_HEADERS = config-host.h
>> +GENERATED_HEADERS = config-host.h trace.h
>>
>> ifneq ($(wildcard config-host.mak),)
>> # Put the all: rule here so that config-host.mak can contain dependencies.
>> @@ -104,16 +104,24 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>>
>> bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
>>
>> +trace.h: $(SRC_PATH)/trace-events config-host.mak
>> +       $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND)
>> -h < $< > $@,"  GEN   $@")
>> +
>> +trace.c: $(SRC_PATH)/trace-events config-host.mak
>> +       $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND)
>> -c < $< > $@,"  GEN   $@")
>> +
>> +trace.o: trace.c $(GENERATED_HEADERS)
>
> There's a dependency issue hidden here: The user emulators recurse into
> *-user with just a dependency on trace.h. The build then fails because the
> target Makefile does not know how to build ../trace.o since the rule is in
> this Makefile instead.
>
> I noticed it with ppc-haiku-user but this should be visible with linux-user
> on a clean build, too.
>
> Adding trace.o or $(trace-obj-y) somewhere before subdir-libuser seems to
> help. I'll post a patch later on if no one beats me.

Your patch would be appreciated.  For the record, in order to reproduce it:
$ make distclean
$ ./configure --target-list=i386-linux-user
$ make
make[1]: *** No rule to make target `../trace.o', needed by `qemu-i386'.  Stop.

If one of the targets does build trace.o then the build completes
successfully.  That's why all targets build works fine.

Stefan
diff mbox

Patch

diff --git a/.gitignore b/.gitignore
index ec6f89f..f3f2bb7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,8 @@  config-devices.*
 config-all-devices.*
 config-host.*
 config-target.*
+trace.h
+trace.c
 *-softmmu
 *-darwin-user
 *-linux-user
diff --git a/Makefile b/Makefile
index f95cc2f..3c5e6a0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@ 
 # Makefile for QEMU.
 
-GENERATED_HEADERS = config-host.h
+GENERATED_HEADERS = config-host.h trace.h
 
 ifneq ($(wildcard config-host.mak),)
 # Put the all: rule here so that config-host.mak can contain dependencies.
@@ -104,16 +104,24 @@  ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 
 bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
 
+trace.h: $(SRC_PATH)/trace-events config-host.mak
+	$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@,"  GEN   $@")
+
+trace.c: $(SRC_PATH)/trace-events config-host.mak
+	$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -c < $< > $@,"  GEN   $@")
+
+trace.o: trace.c $(GENERATED_HEADERS)
+
 ######################################################################
 
 qemu-img.o: qemu-img-cmds.h
 qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS)
 
-qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y)
+qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y)
 
-qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y)
+qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y)
 
-qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y)
+qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y)
 
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
@@ -133,6 +141,7 @@  clean:
 	rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
 	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
 	$(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; \
diff --git a/Makefile.objs b/Makefile.objs
index 4a1eaa1..c61332d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -265,6 +265,11 @@  libdis-$(CONFIG_S390_DIS) += s390-dis.o
 libdis-$(CONFIG_SH4_DIS) += sh4-dis.o
 libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
 
+######################################################################
+# trace
+
+trace-obj-y = trace.o
+
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
diff --git a/Makefile.target b/Makefile.target
index 18826bb..a4e80b1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -310,6 +310,7 @@  obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
 
 endif # CONFIG_SOFTMMU
 
+obj-y += $(addprefix ../, $(trace-obj-y))
 obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 
 $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
diff --git a/configure b/configure
index 146dac0..38613c3 100755
--- a/configure
+++ b/configure
@@ -317,6 +317,7 @@  pkgversion=""
 check_utests="no"
 user_pie="no"
 zero_malloc=""
+trace_backend="nop"
 
 # OS specific
 if check_define __linux__ ; then
@@ -519,6 +520,8 @@  for opt do
   ;;
   --target-list=*) target_list="$optarg"
   ;;
+  --trace-backend=*) trace_backend="$optarg"
+  ;;
   --enable-gprof) gprof="yes"
   ;;
   --static)
@@ -897,6 +900,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"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -2059,6 +2063,18 @@  if compile_prog "" "" ; then
     fdatasync=yes
 fi
 
+##########################################
+# check if trace backend exists
+
+sh "$source_path/tracetool" "--$trace_backend" --check-backend > /dev/null 2> /dev/null
+if test "$?" -ne 0 ; then
+  echo
+  echo "Error: invalid trace backend"
+  echo "Please choose a supported trace backend."
+  echo
+  exit 1
+fi
+
 # End of CC checks
 # After here, no more $cc or $ld runs
 
@@ -2189,6 +2205,7 @@  echo "preadv support    $preadv"
 echo "fdatasync         $fdatasync"
 echo "uuid support      $uuid"
 echo "vhost-net support $vhost_net"
+echo "Trace backend     $trace_backend"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2450,6 +2467,7 @@  bsd)
 ;;
 esac
 
+echo "TRACE_BACKEND=$trace_backend" >> $config_host_mak
 echo "TOOLS=$tools" >> $config_host_mak
 echo "ROMS=$roms" >> $config_host_mak
 echo "MAKE=$make" >> $config_host_mak
diff --git a/trace-events b/trace-events
new file mode 100644
index 0000000..a37d3cc
--- /dev/null
+++ b/trace-events
@@ -0,0 +1,24 @@ 
+# Trace events for debugging and performance instrumentation
+#
+# This file is processed by the tracetool script during the build.
+#
+# To add a new trace event:
+#
+# 1. Choose a name for the trace event.  Declare its arguments and format
+#    string.
+#
+# 2. Call the trace event from code using trace_##name, e.g. multiwrite_cb() ->
+#    trace_multiwrite_cb().  The source file must #include "trace.h".
+#
+# Format of a trace event:
+#
+# <name>(<type1> <arg1>[, <type2> <arg2>] ...) "<format-string>"
+#
+# Example: qemu_malloc(size_t size) "size %zu"
+#
+# The <name> must be a valid as a C function name.
+#
+# Types should be standard C types.  Use void * for pointers because the trace
+# system may not have the necessary headers included.
+#
+# The <format-string> should be a sprintf()-compatible format string.
diff --git a/tracetool b/tracetool
new file mode 100755
index 0000000..01de580
--- /dev/null
+++ b/tracetool
@@ -0,0 +1,175 @@ 
+#!/bin/sh
+#
+# Code generator for trace events
+#
+# Copyright IBM, Corp. 2010
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+
+# Disable pathname expansion, makes processing text with '*' characters simpler
+set -f
+
+usage()
+{
+    cat >&2 <<EOF
+usage: $0 --nop [-h | -c]
+Generate tracing code for a file on stdin.
+
+Backends:
+  --nop Tracing disabled
+
+Output formats:
+  -h    Generate .h file
+  -c    Generate .c file
+EOF
+    exit 1
+}
+
+# Get the name of a trace event
+get_name()
+{
+    echo ${1%%\(*}
+}
+
+# Get the argument list of a trace event, including types and names
+get_args()
+{
+    local args
+    args=${1#*\(}
+    args=${args%)*}
+    echo "$args"
+}
+
+# Get the argument name list of a trace event
+get_argnames()
+{
+    local nfields field name
+    nfields=0
+    for field in $(get_args "$1"); do
+        nfields=$((nfields + 1))
+
+        # Drop pointer star
+        field=${field#\*}
+
+        # Only argument names have commas at the end
+        name=${field%,}
+        test "$field" = "$name" && continue
+
+        printf "%s" "$name, "
+    done
+
+    # Last argument name
+    if [ "$nfields" -gt 1 ]
+    then
+        printf "%s" "$name"
+    fi
+}
+
+# Get the format string for a trace event
+get_fmt()
+{
+    local fmt
+    fmt=${1#*\"}
+    fmt=${fmt%\"*}
+    echo "$fmt"
+}
+
+linetoh_begin_nop()
+{
+    return
+}
+
+linetoh_nop()
+{
+    local name args
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+
+    # Define an empty function for the trace event
+    cat <<EOF
+static inline void trace_$name($args)
+{
+}
+EOF
+}
+
+linetoh_end_nop()
+{
+    return
+}
+
+linetoc_begin_nop()
+{
+    return
+}
+
+linetoc_nop()
+{
+    # No need for function definitions in nop backend
+    return
+}
+
+linetoc_end_nop()
+{
+    return
+}
+
+# Process stdin by calling begin, line, and end functions for the backend
+convert()
+{
+    local begin process_line end
+    begin="lineto$1_begin_$backend"
+    process_line="lineto$1_$backend"
+    end="lineto$1_end_$backend"
+
+    "$begin"
+
+    while read -r str; do
+        # Skip comments and empty lines
+        str=${str%%#*}
+        test -z "$str" && continue
+
+        echo
+        "$process_line" "$str"
+    done
+
+    echo
+    "$end"
+}
+
+tracetoh()
+{
+    cat <<EOF
+#ifndef TRACE_H
+#define TRACE_H
+
+/* This file is autogenerated by tracetool, do not edit. */
+
+#include "qemu-common.h"
+EOF
+    convert h
+    echo "#endif /* TRACE_H */"
+}
+
+tracetoc()
+{
+    echo "/* This file is autogenerated by tracetool, do not edit. */"
+    convert c
+}
+
+# Choose backend
+case "$1" in
+"--nop") backend="${1#--}" ;;
+*) usage ;;
+esac
+shift
+
+case "$1" in
+"-h") tracetoh ;;
+"-c") tracetoc ;;
+"--check-backend") exit 0 ;; # used by ./configure to test for backend
+*) usage ;;
+esac
+
+exit 0