Patchwork [v2,10/23] instrument: [dynamic] Call dynamically linked user-provided routines

login
register
mail settings
Submitter Lluís Vilanova
Date April 16, 2013, 1:50 p.m.
Message ID <20130416135047.21588.78481.stgit@fimbulvetr.bsc.es>
Download mbox | patch
Permalink /patch/236982/
State New
Headers show

Comments

Lluís Vilanova - April 16, 2013, 1:50 p.m.
Provides a mechanism to dynamically change the routine invoked by 'trace_*'.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 .gitignore                                 |    1 
 Makefile                                   |    4 +
 Makefile.objs                              |    6 ++
 configure                                  |    8 ++-
 instrument/Makefile.objs                   |   11 ++++
 libcacard/Makefile                         |    2 -
 scripts/tracetool/__init__.py              |    1 
 scripts/tracetool/backend/instr_dynamic.py |   87 ++++++++++++++++++++++++++++
 scripts/tracetool/format/api_c.py          |   24 ++++++++
 scripts/tracetool/format/events_c.py       |   36 +++++++++++-
 trace/event-internal.h                     |   12 ++++
 11 files changed, 186 insertions(+), 6 deletions(-)
 create mode 100644 scripts/tracetool/backend/instr_dynamic.py
 create mode 100644 scripts/tracetool/format/api_c.py

Patch

diff --git a/.gitignore b/.gitignore
index 2c9695c..2a0ea2f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@  trace/generated-events.h
 trace/generated-events.c
 libcacard/trace/generated-tracers.c
 instrument/generated-tracers.h
+instrument/generated-tracers.c
 instrument/qemu-instr/events.h
 *-timestamp
 *-softmmu
diff --git a/Makefile b/Makefile
index 2d3431a..cf938be 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,9 @@  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
+ifdef CONFIG_TRACE_INSTRUMENT_DYNAMIC
+GENERATED_SOURCES += instrument/generated-tracers.c
+endif
 GENERATED_HEADERS += instrument/qemu-instr/events.h
 
 GENERATED_HEADERS += trace/generated-events.h
@@ -234,6 +237,7 @@  clean:
 	@# May not be present in GENERATED_HEADERS
 	rm -f trace/generated-tracers-dtrace.dtrace*
 	rm -f trace/generated-tracers-dtrace.h*
+	rm -f instrument/generated-tracers.c*
 	rm -f $(foreach f,$(GENERATED_HEADERS),$(f) $(f)-timestamp)
 	rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp)
 	rm -rf qapi-generated
diff --git a/Makefile.objs b/Makefile.objs
index e568c01..5f8ea2d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -91,6 +91,11 @@  common-obj-y += qom/
 common-obj-y += disas/
 
 ######################################################################
+# instrumentation
+
+tools-obj-y += instrument/
+
+######################################################################
 # guest agent
 
 # FIXME: a few definitions from qapi-types.o/qapi-visit.o are needed
@@ -108,5 +113,6 @@  nested-vars += \
 	util-obj-y \
 	qga-obj-y \
 	block-obj-y \
+	tools-obj-y \
 	common-obj-y
 dummy := $(call unnest-vars)
diff --git a/configure b/configure
index 94b9491..41089cc 100755
--- a/configure
+++ b/configure
@@ -1173,7 +1173,7 @@  echo "                           Available backends:" $($python "$source_path"/s
 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 static; default: $trace_instrument)"
+echo "                           Trace instrumentation type (none static dynamic; default: $trace_instrument)"
 echo "  --with-trace-instrument-path=PATH"
 echo "                           Directory to build user-provided static trace event instrumentation library"
 echo "  --disable-spice          disable spice"
@@ -3074,7 +3074,7 @@  fi
 ##########################################
 # Check instrumentation type
 case "$trace_instrument" in
-none|static) ;;
+none|static|dynamic) ;;
 *)       echo "Error: invalid trace instrumentation type: $trace_instrument"
          exit 1
          ;;
@@ -3922,6 +3922,10 @@  if test "$trace_instrument" = "static"; then
     echo "TRACETOOL_INSTR_STATIC=--instr-static-path \"\$(TRACE_INSTRUMENT_PATH)\"" >> $config_host_mak
     QEMU_CFLAGS="-I\"$trace_instrument_path\" $QEMU_CFLAGS"
 fi
+if test "$trace_instrument" = "dynamic"; then
+    echo "#define QI_TYPE_DYNAMIC 1" >> $config_qi
+    echo "CONFIG_TRACE_INSTRUMENT_DYNAMIC=y" >> $config_host_mak
+fi
 ##########################################
 
 echo "TOOLS=$tools" >> $config_host_mak
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
index 4102b59..cae520d 100644
--- a/instrument/Makefile.objs
+++ b/instrument/Makefile.objs
@@ -17,6 +17,17 @@  ifdef CONFIG_TRACE_INSTRUMENT_STATIC
 .PHONY: $(obj)/generated-tracers.h-timestamp
 endif
 
+$(obj)/generated-tracers.c: $(obj)/generated-tracers.c-timestamp
+$(obj)/generated-tracers.c-timestamp: $(TRACE_EVENTS) $(BUILD_DIR)/config-host.mak
+	$(call quiet-command,$(TRACETOOL) \
+		--format=api-c \
+		--backend=$(TRACE_INSTRUMENT_BACKEND) \
+		< $< > $@,"  GEN   $(patsubst %-timestamp,%,$@)")
+	@cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@)
+
+tools-obj-$(CONFIG_TRACE_INSTRUMENT_DYNAMIC) += generated-tracers.o
+target-obj-$(CONFIG_TRACE_INSTRUMENT_DYNAMIC) += generated-tracers.o
+
 
 ######################################################################
 # User interface
diff --git a/libcacard/Makefile b/libcacard/Makefile
index c0a5d66..f3f9f28 100644
--- a/libcacard/Makefile
+++ b/libcacard/Makefile
@@ -7,7 +7,7 @@  libcacard-obj-y = $(stub-obj-y) $(libcacard-y)
 libcacard-obj-y += util/osdep.o util/cutils.o util/qemu-timer-common.o util/error.o
 libcacard-obj-$(CONFIG_WIN32) += util/oslib-win32.o util/qemu-thread-win32.o
 libcacard-obj-$(CONFIG_POSIX) += util/oslib-posix.o util/qemu-thread-posix.o
-libcacard-obj-y += $(filter trace/%, $(util-obj-y))
+libcacard-obj-y += $(filter trace/%, $(util-obj-y)) $(filter instrument/%, $(util-obj-y))
 
 libcacard-lobj-y=$(patsubst %.o,%.lo,$(libcacard-obj-y))
 
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
index 5406a2b..7624982 100644
--- a/scripts/tracetool/__init__.py
+++ b/scripts/tracetool/__init__.py
@@ -182,6 +182,7 @@  class Event(object):
     QI_TRACE_INSTRUMENT     = "qi_event_%(name)s"
     QI_TRACE_NOP            = "qi_event_%(name)s_nop"
     QI_TRACE_BACKEND        = "qi_event_%(name)s_trace"
+    QI_TRACE_CB             = QI_TRACE_NOP
 
     def api(self, fmt = None):
         if fmt is None:
diff --git a/scripts/tracetool/backend/instr_dynamic.py b/scripts/tracetool/backend/instr_dynamic.py
new file mode 100644
index 0000000..a07ee64
--- /dev/null
+++ b/scripts/tracetool/backend/instr_dynamic.py
@@ -0,0 +1,87 @@ 
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Dynamic 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):
+    for e in events:
+        if "instrument" not in e.properties:
+            continue
+
+        out('extern void * %(qi)s_cb;',
+            'static inline void %(qi)s(%(args)s)',
+            '{',
+            '    ((void (*)(%(argtypes)s))%(qi)s_cb)(%(argnames)s);',
+            '}',
+            qi = e.api(e.QI_TRACE_INSTRUMENT),
+            args = e.args,
+            argnames = ", ".join(e.args.names()),
+            argtypes = ", ".join(e.args.types()),
+            )
+
+    tracetool.format.qemu_h.process_common(events)
+
+
+
+def api_h(events):
+    out('#include <qemu-instr/visibility-internal.h>',
+        '',
+        )
+
+    for e in events:
+        if "instrument" not in e.properties:
+            continue
+
+        out('QI_VPUBLIC void %(qi)s(%(args)s);',
+            'void %(qi_nop)s(%(args)s);',
+            'void %(qi_backend)s(%(args)s);',
+            qi = e.api(e.QI_TRACE_INSTRUMENT),
+            qi_nop = e.api(e.QI_TRACE_NOP),
+            qi_backend = e.api(e.QI_TRACE_BACKEND),
+            args = e.args,
+            )
+
+def api_c(events):
+    out('#include "instrument/qemu-instr/events.h"',
+        '',
+        '#include "trace/generated-events.h"',
+        '#include "trace/generated-tracers.h"',
+        '',
+        )
+
+    for e in events:
+        if "instrument" not in e.properties:
+            continue
+
+        out('void %(qi_nop)s(%(args)s)',
+            '{',
+            '}',
+            '',
+            'void %(qi_backend)s(%(args)s)',
+            '{',
+            '    %(qemu_backend)s(%(argnames)s);',
+            '}',
+            '',
+            'void * %(qi)s_cb = %(qi_cb)s;',
+            qi = e.api(e.QI_TRACE_INSTRUMENT),
+            qi_nop = e.api(e.QI_TRACE_NOP),
+            qi_backend = e.api(e.QI_TRACE_BACKEND),
+            qi_cb = e.api(e.QI_TRACE_CB),
+            qemu_backend = e.api(e.QEMU_TRACE_BACKEND),
+            args = e.args,
+            argnames = ", ".join(e.args.names()),
+            )
diff --git a/scripts/tracetool/format/api_c.py b/scripts/tracetool/format/api_c.py
new file mode 100644
index 0000000..3787f5d
--- /dev/null
+++ b/scripts/tracetool/format/api_c.py
@@ -0,0 +1,24 @@ 
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .c 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. */',
+        '',
+        '#include <stdlib.h>',
+        '',
+        )
diff --git a/scripts/tracetool/format/events_c.py b/scripts/tracetool/format/events_c.py
index d670ec8..7531c66 100644
--- a/scripts/tracetool/format/events_c.py
+++ b/scripts/tracetool/format/events_c.py
@@ -6,7 +6,7 @@  Generate .c for event description.
 """
 
 __author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
-__copyright__  = "Copyright 2012, 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"
@@ -19,17 +19,49 @@  from tracetool import out
 def begin(events):
     out('/* This file is autogenerated by tracetool, do not edit. */',
         '',
+        '#include "config-host.h"',
         '#include "trace.h"',
         '#include "trace/generated-events.h"',
         '#include "trace/control.h"',
         '',
         )
 
+    # declarations
+    out('#if defined(CONFIG_TRACE_INSTRUMENT_DYNAMIC)')
+    for e in events:
+        if "instrument" in e.properties:
+            out('void %(nop)s(%(args)s);',
+                'void %(backend)s(%(args)s);',
+                nop = e.api(e.QI_TRACE_NOP),
+                backend = e.api(e.QI_TRACE_BACKEND),
+                args = e.args,
+                )
+    out('#endif',
+        '',
+        )
+
+    # event state
     out('TraceEvent trace_events[TRACE_EVENT_COUNT] = {')
 
     for e in events:
-        out('    { .id = %(id)s, .name = \"%(name)s\", .sstate = %(sstate)s, .dstate = 0 },',
+        cb = cb_nop = cb_backend = "NULL"
+
+        if "instrument" in e.properties:
+            cb = "&%s_cb" % e.api(e.QI_TRACE_INSTRUMENT)
+            cb_nop = e.api(e.QI_TRACE_NOP)
+            cb_backend = e.api(e.QI_TRACE_BACKEND)
+
+        out('    { .id = %(id)s, .name = \"%(name)s\", .sstate = %(sstate)s, .dstate = 0,',
+            '#if defined(CONFIG_TRACE_INSTRUMENT_DYNAMIC)',
+            '      .instr_cb = %(cb)s,',
+            '      .instr_cb_nop = %(cb_nop)s,',
+            '      .instr_cb_backend = %(cb_backend)s,',
+            '#endif',
+            '    },',
             id = "TRACE_" + e.name.upper(),
+            cb = cb,
+            cb_nop = cb_nop,
+            cb_backend = cb_backend,
             name = e.name,
             sstate = "TRACE_%s_ENABLED" % e.name.upper(),
             )
diff --git a/trace/event-internal.h b/trace/event-internal.h
index b2310d9..aed4050 100644
--- a/trace/event-internal.h
+++ b/trace/event-internal.h
@@ -1,7 +1,7 @@ 
 /*
  * Interface for configuring and controlling the state of tracing events.
  *
- * Copyright (C) 2012 Lluís Vilanova <vilanova@ac.upc.edu>
+ * Copyright (C) 2012-2013 Lluís Vilanova <vilanova@ac.upc.edu>
  *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
@@ -11,6 +11,7 @@ 
 #define TRACE__EVENT_INTERNAL_H
 
 #include "trace/generated-events.h"
+#include "config-host.h"
 
 
 /**
@@ -19,6 +20,9 @@ 
  * @name: Event name.
  * @sstate: Static tracing state.
  * @dstate: Dynamic tracing state.
+ * @instr_cb: Instrumentation callback pointer.
+ * @instr_cb_nop: Instrumentation callback pointer to no-operation.
+ * @instr_cb_backend: Instrumentation callback pointer to tracing backend.
  *
  * Opaque generic description of a tracing event.
  */
@@ -27,6 +31,12 @@  typedef struct TraceEvent {
     const char * name;
     const bool sstate;
     bool dstate;
+
+#if defined(CONFIG_TRACE_INSTRUMENT_DYNAMIC)
+    void **instr_cb;
+    void *instr_cb_nop;
+    void *instr_cb_backend;
+#endif
 } TraceEvent;