@@ -10,6 +10,8 @@ trace/generated-tracers.dtrace
trace/generated-events.h
trace/generated-events.c
libcacard/trace/generated-tracers.c
+instrument/generated-tracers.h
+instrument/qemu-instr/events.h
*-timestamp
*-softmmu
*-darwin-user
@@ -35,6 +35,9 @@ GENERATED_HEADERS = config-host.h qemu-options.def
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c
+GENERATED_HEADERS += instrument/generated-tracers.h
+GENERATED_HEADERS += instrument/qemu-instr/events.h
+
GENERATED_HEADERS += trace/generated-events.h
GENERATED_SOURCES += trace/generated-events.c
@@ -224,6 +224,7 @@ zero_malloc=""
trace_events=`dirname $0`/trace-events
trace_backend="nop"
trace_file="trace"
+trace_instrument="none"
spice=""
rbd=""
smartcard_nss=""
@@ -646,6 +647,8 @@ for opt do
;;
--with-trace-file=*) trace_file="$optarg"
;;
+ --with-trace-instrument=*) trace_instrument="$optarg"
+ ;;
--enable-gprof) gprof="yes"
;;
--enable-gcov) gcov="yes"
@@ -1166,6 +1169,8 @@ echo " --enable-trace-backend=B Set trace backend"
echo " Available backends:" $($python "$source_path"/scripts/tracetool.py --list-backends)
echo " --with-trace-file=NAME Full PATH,NAME of file to store traces"
echo " Default:trace-<pid>"
+echo " --with-trace-instrument=TYPE"
+echo " Trace instrumentation type (none; default: $trace_instrument)"
echo " --disable-spice disable spice"
echo " --enable-spice enable spice"
echo " --enable-rbd enable building the rados block device (rbd)"
@@ -3062,6 +3067,15 @@ if test "$trace_backend" = "dtrace"; then
fi
##########################################
+# Check instrumentation type
+case "$trace_instrument" in
+none) ;;
+*) echo "Error: invalid trace instrumentation type: $trace_instrument"
+ exit 1
+ ;;
+esac
+
+##########################################
# __sync_fetch_and_and requires at least -march=i486. Many toolchains
# use i686 as default anyway, but for those that don't, an explicit
# specification is necessary
@@ -3437,6 +3451,7 @@ echo "vhost-net support $vhost_net"
echo "Trace events $trace_events"
echo "Trace backend $trace_backend"
echo "Trace output file $trace_file-<pid>"
+echo "Trace instrument $trace_instrument"
echo "spice support $spice ($spice_protocol_version/$spice_server_version)"
echo "rbd support $rbd"
echo "xfsctl support $xfs"
@@ -3859,6 +3874,22 @@ if test "$trace_default" = "yes"; then
echo "CONFIG_TRACE_DEFAULT=y" >> $config_host_mak
fi
+##########################################
+# trace instrumentation
+config_qi=instrument/qemu-instr/config.h
+mkdir -p `dirname $config_qi`
+echo "/* Automatically generated by configure - do not modify */" > $config_qi
+
+echo "TRACE_INSTRUMENT_BACKEND=instr-$trace_instrument" >> $config_host_mak
+
+if test "$trace_instrument" = "none"; then
+ echo "#define QI_TYPE_NONE 1" >> $config_qi
+ echo "CONFIG_TRACE_INSTRUMENT_NONE=y" >> $config_host_mak
+else
+ echo "CONFIG_TRACE_INSTRUMENT=y" >> $config_host_mak
+fi
+##########################################
+
echo "TOOLS=$tools" >> $config_host_mak
echo "ROMS=$roms" >> $config_host_mak
echo "MAKE=$make" >> $config_host_mak
@@ -1,6 +1,6 @@
#ifndef TRACE_H
#define TRACE_H
-#include "trace/generated-tracers.h"
+#include "instrument/generated-tracers.h"
#endif /* TRACE_H */
new file mode 100644
@@ -0,0 +1,24 @@
+# -*- mode: makefile -*-
+
+######################################################################
+# QEMU trace->instrument interface
+
+$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp
+$(obj)/generated-tracers.h-timestamp: $(TRACE_EVENTS) $(BUILD_DIR)/config-host.mak
+ $(call quiet-command,$(TRACETOOL) \
+ --format=qemu-h \
+ --backend=$(TRACE_INSTRUMENT_BACKEND) \
+ < $< > $@," GEN $(patsubst %-timestamp,%,$@)")
+ @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@)
+
+
+######################################################################
+# User interface
+
+$(obj)/qemu-instr/events.h: $(obj)/qemu-instr/events.h-timestamp
+$(obj)/qemu-instr/events.h-timestamp: $(TRACE_EVENTS) $(BUILD_DIR)/config-host.mak
+ $(call quiet-command,$(TRACETOOL) \
+ --format=api-h \
+ --backend=$(TRACE_INSTRUMENT_BACKEND) \
+ < $< > $@," GEN $(patsubst %-timestamp,%,$@)")
+ @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@)
@@ -122,7 +122,7 @@ class Event(object):
_CRE = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?")
- _VALID_PROPS = set(["disable"])
+ _VALID_PROPS = set(["disable", "instrument"])
def __init__(self, name, props, fmt, args):
"""
@@ -146,6 +146,9 @@ class Event(object):
if len(unknown_props) > 0:
raise ValueError("Unknown properties: %s" % ", ".join(unknown_props))
+ if "instrument" in self.properties and "disable" in self.properties:
+ raise ValueError("Cannot instrument a disabled event: %s" % self.name)
+
@staticmethod
def build(line_str):
"""Build an Event instance from a string.
@@ -175,10 +178,12 @@ class Event(object):
QEMU_TRACE = "trace_%(name)s"
+ QEMU_TRACE_BACKEND = "trace_%(name)s_backend"
+ QI_TRACE_INSTRUMENT = "qi_event_%(name)s"
def api(self, fmt = None):
if fmt is None:
- fmt = Event.QEMU_TRACE
+ fmt = Event.QEMU_TRACE_BACKEND
return fmt % { "name" : self.name }
def _read_events(fobj):
new file mode 100644
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+No-instrumentation proxy.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2013, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+import tracetool.format.qemu_h
+
+
+def qemu_h(events):
+ out('#include "instrument/qemu-instr/events.h"',
+ '',
+ )
+ tracetool.format.qemu_h.process_common(events)
+
+
+def api_h(events):
+ for e in events:
+ if "instrument" not in e.properties:
+ continue
+
+ out('static inline void %(qi)s(%(args)s)',
+ '{',
+ ' %(qemu_backend)s(%(argnames)s);',
+ '}',
+ '',
+ qi = e.api(e.QI_TRACE_INSTRUMENT),
+ args = e.args,
+ qemu_backend = e.api(e.QEMU_TRACE_BACKEND),
+ argnames = ", ".join(e.args.names()),
+ )
new file mode 100644
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .h for trace instrumentation clients.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2013, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+ out('/* This file is autogenerated by tracetool, do not edit. */',
+ '',
+ '#ifndef QI__EVENTS_H',
+ '#define QI__EVENTS_H',
+ '',
+ '#ifdef __cplusplus',
+ 'extern "C" {',
+ '#endif',
+ '',
+ '#include <stdint.h>',
+ '',
+ )
+
+def end(events):
+ out('#ifdef __cplusplus',
+ '}',
+ '#endif',
+ '',
+ '#endif /* QI__EVENTS_H */',
+ )
new file mode 100644
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .h for trace instrumentation proxy.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2013, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+ out('/* This file is autogenerated by tracetool, do not edit. */',
+ '',
+ '#ifndef INSTRUMENT__GENERATED_TRACERS_H',
+ '#define INSTRUMENT__GENERATED_TRACERS_H',
+ '',
+ '#include "trace/generated-tracers.h"',
+ '',
+ )
+
+def end(events):
+ out('#include "trace/generated-events.h"',
+ '',
+ '#endif /* INSTRUMENT__GENERATED_TRACERS_H */',
+ )
+
+def nop(events):
+ for e in events:
+ out('static inline void %(qemu)s(%(args)s)',
+ '{',
+ ' %(qemu_backend)s(%(argnames)s);',
+ '}',
+ '',
+ qemu = e.api(e.QEMU_TRACE),
+ args = e.args,
+ qemu_backend = e.api(e.QEMU_TRACE_BACKEND),
+ argnames = ", ".join(e.args.names()),
+ )
+
+def process_common(events):
+ for e in events:
+ if "instrument" not in e.properties:
+ nop([e])
+ continue
+
+ out('static inline void %(qemu)s(%(args)s)',
+ '{',
+ '#if defined(QEMU_TOOLS)',
+ ' %(backend)s(%(argnames)s);',
+ '#else',
+ ' %(qi)s(%(argnames)s);',
+ '#endif',
+ '}',
+ '',
+ qemu = e.api(e.QEMU_TRACE),
+ args = e.args,
+ qi = e.api(e.QI_TRACE_INSTRUMENT),
+ backend = e.api(e.QEMU_TRACE_BACKEND),
+ argnames = ", ".join(e.args.names()),
+ )
Splits the QEMU-side tracing interface into different layers (in order of nested invocation): * trace_* The interface used by QEMU code to signal traceable/instrumentable events (now generated according to the selected instrumentation type). * qi_event_* The interface provided by the user's instrumentation code (for which QEMU provides default implementations depending on the instrumentation type). * qi_event_*_trace / qi_event_*_nop The interface provided by QEMU to the user's instrumentation code to invoke the tracing backend. The nop variant simply does nothing. * trace_*_backend The interface provided by the tracing backend in QEMU. Originally exposed as 'trace_*' routines. The 'none' instrumentation type (this one) skips through the qi_* layers and directly calls 'trace_*_backend' from the 'trace_*' routines (providing the original tracing behaviour). Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- .gitignore | 2 + Makefile | 3 + configure | 31 ++++++++++++++ include/trace.h | 2 - instrument/Makefile.objs | 24 +++++++++++ scripts/tracetool/__init__.py | 9 +++- scripts/tracetool/backend/instr_none.py | 41 +++++++++++++++++++ scripts/tracetool/format/api_h.py | 39 ++++++++++++++++++ scripts/tracetool/format/qemu_h.py | 68 +++++++++++++++++++++++++++++++ 9 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 instrument/Makefile.objs create mode 100644 scripts/tracetool/backend/instr_none.py create mode 100644 scripts/tracetool/format/api_h.py create mode 100644 scripts/tracetool/format/qemu_h.py