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