From: Lluís Vilanova <vilan...@ac.upc.edu>

Signed-off-by: Lluís Vilanova <vilan...@ac.upc.edu>
Signed-off-by: Harsh Prateek Bora <ha...@linux.vnet.ibm.com>
---
 Makefile.objs        |    6 +-
 Makefile.target      |    3 +-
 scripts/tracetool.py |  321 ++++++++++++++++++++++++++++++++------------------
 3 files changed, 211 insertions(+), 119 deletions(-)

diff --git a/Makefile.objs b/Makefile.objs
index 984034a..acb51b6 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -344,12 +344,12 @@ else
 trace.h: trace.h-timestamp
 endif
 trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
-       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py 
--backend=$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py 
--format=h --backend=$(TRACE_BACKEND) < $< > $@,"  GEN   trace.h")
        @cmp -s $@ trace.h || cp $@ trace.h
 
 trace.c: trace.c-timestamp
 trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
-       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py 
--backend=$(TRACE_BACKEND) -c < $< > $@,"  GEN   trace.c")
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py 
--format=c --backend=$(TRACE_BACKEND) < $< > $@,"  GEN   trace.c")
        @cmp -s $@ trace.c || cp $@ trace.c
 
 trace.o: trace.c $(GENERATED_HEADERS)
@@ -362,7 +362,7 @@ trace-dtrace.h: trace-dtrace.dtrace
 # rule file. So we use '.dtrace' instead
 trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
 trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events 
$(BUILD_DIR)/config-host.mak
-       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py 
--backend=$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py 
--format=d --backend=$(TRACE_BACKEND) < $< > $@,"  GEN   trace-dtrace.dtrace")
        @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
 
 trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
diff --git a/Makefile.target b/Makefile.target
index 07b21d1..6706767 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -51,11 +51,12 @@ endif
 
 $(QEMU_PROG).stp:
        $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py \
+               --format=stap \
                --backend=$(TRACE_BACKEND) \
                --binary=$(bindir)/$(QEMU_PROG) \
                --target-arch=$(TARGET_ARCH) \
                --target-type=$(TARGET_TYPE) \
-               --stap < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp,"  GEN   
$(QEMU_PROG).stp")
+               < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp,"  GEN   
$(QEMU_PROG).stp")
 else
 stap:
 endif
diff --git a/scripts/tracetool.py b/scripts/tracetool.py
index 2d6f9ee..947b808 100755
--- a/scripts/tracetool.py
+++ b/scripts/tracetool.py
@@ -12,33 +12,107 @@ import sys
 import getopt
 import re
 
-def usage():
-    print "Tracetool: Generate tracing code for trace events file on stdin"
-    print "Usage:"
-    print sys.argv[0], "--backend=[nop|simple|stderr|dtrace|ust] 
[-h|-c|-d|--stap]"
-    print '''
-Backends:
-  --nop     Tracing disabled
-  --simple  Simple built-in backend
-  --stderr  Stderr built-in backend
-  --dtrace  DTrace/SystemTAP backend
-  --ust     LTTng User Space Tracing backend
-
-Output formats:
-  -h     Generate .h file
-  -c     Generate .c file
-  -d     Generate .d file (DTrace only)
-  --stap Generate .stp file (DTrace with SystemTAP only)
+######################################################################
+# format auto-registration
+
+class _Tag:
+    pass
+
+_formats = {}
+
+BEGIN = _Tag()
+END = _Tag()
+_DESCR = _Tag()
+
+def for_format(format_, when, descr = None):
+    """Decorator for format generator functions."""
+
+    if when is not BEGIN and when is not END:
+        raise ValueError("Invalid 'when' tag")
+    if format_ in _formats and when in _formats[format_]:
+        raise ValueError("Format '%s' already set for given 'when' tag" % 
format_)
+
+    if format_ not in _formats:
+        _formats[format_] = {}
+    if descr is not None:
+        if _DESCR in _formats[format_]:
+            raise ValueError("Description already set")
+        _formats[format_][_DESCR] = descr
+
+    def func(f):
+        _formats[format_][when] = f
+        return f
+    return func
+
+def get_format(format_, when):
+    """Get a format generator function."""
+
+    def nop(*args, **kwargs):
+        pass
+    if format_ in _formats and when in _formats[format_]:
+        return _formats[format_][when]
+    else:
+        return nop
+
+def get_format_descr(format_):
+    """Get the description of a format generator."""
+
+    if format_ in _formats and _DESCR in _formats[format_]:
+        return _formats[format_][_DESCR]
+    else:
+        return ""
 
-Options:
-  --binary       [path]    Full path to QEMU binary
-  --target-arch  [arch]    QEMU emulator target arch
-  --target-type  [type]    QEMU emulator target type ('system' or 'user')
-  --probe-prefix [prefix]  Prefix for dtrace probe names
-                           (default: qemu-targettype-targetarch)
-'''
-    sys.exit(1)
 
+
+######################################################################
+# backend auto-registration and format compatibility
+
+_backends = {}
+
+def for_backend(backend, format_, descr = None):
+    if backend not in _backends:
+        _backends[backend] = {}
+    if format_ in _backends[backend]:
+        raise ValueError("Backend '%s' already set for backend '%s'" % 
(backend, format_))
+    if format_ not in _formats:
+        raise ValueError("Unknown format '%s'" % format_)
+
+    if descr is not None:
+        if _DESCR in _backends[backend]:
+            raise ValueError("Description already set")
+        _backends[backend][_DESCR] = descr
+
+    def func(f):
+        _backends[backend][format_] = f
+        return f
+    return func
+
+def get_backend(format_, backend):
+    if backend not in _backends:
+        raise ValueError("Unknown backend '%s'" % backend)
+    if format_ not in _formats:
+        raise ValueError("Unknown format '%s'" % format_)
+    if format_ not in _backends[backend]:
+        raise ValueError("Format '%s' not supported with backend '%s'" % 
(format_, backend))
+    return _backends[backend][format_]
+
+def get_backend_descr(backend):
+    """Get the description of a backend."""
+
+    if backend in _backends and _DESCR in _backends[backend]:
+        return _backends[backend][_DESCR]
+    else:
+        return ""
+
+
+
+######################################################################
+# formats
+
+##################################################
+# format: h
+
+@for_format("h", BEGIN, "Generate .h file")
 def trace_h_begin(events):
     print '''#ifndef TRACE_H
 #define TRACE_H
@@ -47,12 +121,27 @@ def trace_h_begin(events):
 
 #include "qemu-common.h"'''
 
+@for_format("h", END)
 def trace_h_end(events):
     print '#endif /* TRACE_H */'
 
+
+##################################################
+# format: c
+
+@for_format("c", BEGIN, "Generate .c file")
 def trace_c_begin(events):
     print '/* This file is autogenerated by tracetool, do not edit. */'
 
+
+
+######################################################################
+# backends
+
+##################################################
+# backend: nop
+
+@for_backend("nop", "h", "Tracing disabled")
 def nop_h(events):
     print
     for event in events:
@@ -63,11 +152,15 @@ def nop_h(events):
     'name': event.name,
     'args': event.args
 }
-    return
 
+@for_backend("nop", "c")
 def nop_c(events):
     pass # nop, reqd for converters
 
+##################################################
+# backend: simple
+
+@for_backend("simple", "h", "Simple built-in backend")
 def simple_h(events):
     print '#include "trace/simple.h"'
     print
@@ -95,6 +188,7 @@ def simple_h(events):
     print 'extern TraceEvent trace_list[NR_TRACE_EVENTS];'
 
 
+@for_backend("simple", "c")
 def simple_c(events):
     print '#include "trace.h"'
     print
@@ -108,6 +202,10 @@ def simple_c(events):
         print
     print '};'
 
+##################################################
+# backend: stderr
+
+@for_backend("stderr", "h", "Stderr built-in backend")
 def stderr_h(events):
     print '''#include <stdio.h>
 #include "trace/stderr.h"
@@ -133,6 +231,7 @@ static inline void trace_%(name)s(%(args)s)
     print
     print '#define NR_TRACE_EVENTS %d' % len(events)
 
+@for_backend("stderr", "c")
 def stderr_c(events):
     print '''#include "trace.h"
 
@@ -145,6 +244,11 @@ TraceEvent trace_list[] = {
         print
     print '};'
 
+
+##################################################
+# backend: ust
+
+@for_backend("ust", "h", "LTTng User Space Tracing backend")
 def ust_h(events):
     print '''#include <ust/tracepoint.h>
 #undef mutex_lock
@@ -169,6 +273,7 @@ _DECLARE_TRACEPOINT_NOARGS(ust_%(name)s);
 }
     print
 
+@for_backend("ust", "c")
 def ust_c(events):
     print '''#include <ust/marker.h>
 #undef mutex_lock
@@ -214,6 +319,10 @@ static void __attribute__((constructor)) trace_init(void)
 }
     print '}'
 
+##################################################
+# backend: dtrace
+
+@for_backend("dtrace", "h", "DTrace/SystemTAP backend")
 def dtrace_h(events):
     print '#include "trace-dtrace.h"'
     print
@@ -230,9 +339,15 @@ def dtrace_h(events):
     'argnames': ", ".join(event.args.names()),
 }
 
+@for_backend("dtrace", "c")
 def dtrace_c(events):
     pass # No need for function definitions in dtrace backend
 
+@for_format("d", BEGIN, "Generate .d file (DTrace probes)")
+def trace_d_begin(events):
+    print '/* This file is autogenerated by tracetool, do not edit. */'
+
+@for_backend("dtrace", "d")
 def dtrace_d(events):
     print 'provider qemu {'
     for event in events:
@@ -252,9 +367,15 @@ def dtrace_d(events):
     print
     print '};'
 
+@for_backend("nop", "d")
 def dtrace_nop_d(events):
     pass
 
+
+@for_format("stap", BEGIN, "Generate .stp file (SystemTAP tapsets)")
+def trace_stap_begin(events):
+    print '/* This file is autogenerated by tracetool, do not edit. */'
+
 def dtrace_stp(events):
     for event in events:
         # Define prototype for probe arguments
@@ -279,64 +400,9 @@ probe %(probeprefix)s.%(name)s = 
process("%(binary)s").mark("%(name)s")
 def dtrace_nop_stp(events):
     pass
 
-def trace_stap_begin(events):
-    print '/* This file is autogenerated by tracetool, do not edit. */'
-
-def trace_d_begin(events):
-    print '/* This file is autogenerated by tracetool, do not edit. */'
-
-
-# Registry of backends and their converter functions
-converters = {
-    'simple': {
-        'h': simple_h,
-        'c': simple_c,
-    },
-
-    'nop': {
-        'h': nop_h,
-        'c': nop_c,
-        'd': dtrace_nop_d,
-        'stap': dtrace_nop_stp,
-    },
-
-    'stderr': {
-        'h': stderr_h,
-        'c': stderr_c,
-    },
-
-    'dtrace': {
-        'h': dtrace_h,
-        'c': dtrace_c,
-        'd': dtrace_d,
-        'stap': dtrace_stp
-    },
-
-    'ust': {
-        'h': ust_h,
-        'c': ust_c,
-    },
-
-}
-
-# Trace file header and footer code generators
-formats = {
-    'h': {
-        'begin': trace_h_begin,
-        'end': trace_h_end,
-    },
-    'c': {
-        'begin': trace_c_begin,
-    },
-    'd': {
-        'begin': trace_d_begin,
-    },
-    'stap': {
-        'begin': trace_stap_begin,
-    },
-}
-
+######################################################################
 # Event arguments
+
 def type_is_string(type_):
     strtype = ('const char*', 'char*', 'const char *', 'char *')
     return type_.lstrip().startswith(strtype)
@@ -377,7 +443,10 @@ class Arguments:
         res = ""
         return res
 
+
+######################################################################
 # A trace event
+
 cre = 
re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?")
 
 VALID_PROPS = set(["disable"])
@@ -407,32 +476,51 @@ def read_events(fobj):
         res.append(Event(line))
     return res
 
+######################################################################
+# Main
+
+format_ = ""
 binary = ""
 probeprefix = ""
 
+def usage():
+    print "Tracetool: Generate tracing code for trace events file on stdin"
+    print "Usage:"
+    print sys.argv[0], " --format=<format> --backend=<backend>"
+    print
+    print "Output formats:"
+    for f in _formats:
+        print "   %-10s %s" % (f, get_format_descr(f))
+    print
+    print "Backends:"
+    for b in _backends:
+        print "   %-10s %s" % (b, get_backend_descr(b))
+    print """
+Options:
+  --binary       [path]    Full path to QEMU binary
+  --target-arch  [arch]    QEMU emulator target arch
+  --target-type  [type]    QEMU emulator target type ('system' or 'user')
+  --probe-prefix [prefix]  Prefix for dtrace probe names
+                           (default: qemu-targettype-targetarch)
+"""
+
+    sys.exit(1)
+
 def main():
-    global binary, probeprefix
+    global format_, binary, probeprefix
     targettype = ""
     targetarch = ""
-    supported_backends = ["simple", "nop", "stderr", "dtrace", "ust"]
-    short_options = "hcd"
-    long_options = ["stap", "backend=", "binary=", "target-arch=", 
"target-type=", "probe-prefix=", "list-backends", "check-backend"]
+    long_options = ["format=", "backend=", "binary=", "target-arch=", 
"target-type=", "probe-prefix=", "list-backends", "check-backend"]
     try:
-        opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
+        opts, args = getopt.getopt(sys.argv[1:], "", long_options)
     except getopt.GetoptError, err:
         # print help information and exit:
         print str(err) # will print something like "option -a not recognized"
         usage()
         sys.exit(2)
     for opt, arg in opts:
-        if opt == '-h':
-            output = 'h'
-        elif opt == '-c':
-            output = 'c'
-        elif opt == '-d':
-            output = 'd'
-        elif opt == '--stap':
-            output = 'stap'
+        if opt == '--format':
+            format_ = arg
         elif opt == '--backend':
             backend = arg
         elif opt == '--binary':
@@ -444,30 +532,27 @@ def main():
         elif opt == '--probe-prefix':
             probeprefix = arg
         elif opt == '--list-backends':
-            print 'simple, nop, stderr, dtrace, ust'
+            print ', '.join(_backends)
             sys.exit(0)
         elif opt == "--check-backend":
-            if any(backend in s for s in supported_backends):
+            if backend in _backends:
                 sys.exit(0)
             else:
                 sys.exit(1)
         else:
-            #assert False, "unhandled option"
             print "unhandled option: ", opt
             usage()
 
-    if backend == "" or output == "":
+    if format_ not in _formats:
+        print "Unknown format: %s" % format_
+        print
+        usage()
+    if backend not in _backends:
+        print "Unknown backend: %s" % backend
+        print
         usage()
-        sys.exit(0)
-
-    if backend != 'dtrace' and output == 'd':
-        print 'DTrace probe generator not applicable to %s backend' % backend
-        sys.exit(1)
 
-    if output == 'stap':
-        if backend != "dtrace":
-            print 'SystemTAP tapset generator not applicable to %s backend' % 
backend
-            sys.exit(1)
+    if format_ == 'stap':
         if binary == "":
             print '--binary is required for SystemTAP tapset generator'
             sys.exit(1)
@@ -482,12 +567,18 @@ def main():
 
     events = read_events(sys.stdin)
 
-    if 'begin' in formats[output]:
-        formats[output]['begin'](events)
-    converters[backend][output]([ e for e in events if 'disable' not in 
e.properties ])
-    converters['nop'][output]([ e for e in events if 'disable' in e.properties 
])
-    if 'end' in formats[output]:
-        formats[output]['end'](events)
+    try:
+        # just force format/backend compatibility check
+        bfun = get_backend(format_, backend)
+        bnop = get_backend(format_, "nop")
+    except Exception as e:
+        sys.stderr.write(str(e) + "\n\n")
+        usage()
+
+    get_format(format_, BEGIN)(events)
+    bfun([ e for e in events if "disable" not in e.properties ])
+    bnop([ e for e in events if "disable" in e.properties ])
+    get_format(format_, END)(events)
 
 if __name__ == "__main__":
     main()
-- 
1.7.1.1


Reply via email to