From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:38707) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S7Xwh-0003UV-O7 for qemu-devel@nongnu.org; Tue, 13 Mar 2012 16:03:50 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S7Xwa-00082L-23 for qemu-devel@nongnu.org; Tue, 13 Mar 2012 16:03:47 -0400 Received: from roura.ac.upc.es ([147.83.33.10]:38922) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S7XwZ-000827-FO for qemu-devel@nongnu.org; Tue, 13 Mar 2012 16:03:39 -0400 From: =?utf-8?b?TGx1w61z?= Vilanova Date: Tue, 13 Mar 2012 21:03:32 +0100 Message-Id: <20120313200332.24179.78152.stgit@ginnungagap.bsc.es> In-Reply-To: <20120313200235.24179.63987.stgit@ginnungagap.bsc.es> References: <20120313200235.24179.63987.stgit@ginnungagap.bsc.es> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH 10/12] trace: [tracetool] Automatically establish available backends and formats List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: stefanha@gmail.com, harsh@linux.vnet.ibm.com, aneesh.kumar@linux.vnet.ibm.com Adds decorators to establish which backend and/or format each routine is = meant to process. With this, tables enumerating format and backend routines can be eliminat= ed and part of the usage message can be computed in a more generic way. Signed-off-by: Llu=C3=ADs Vilanova Signed-off-by: Harsh Prateek Bora --- Makefile.objs | 6 - Makefile.target | 3=20 scripts/tracetool.py | 320 ++++++++++++++++++++++++++++++++------------= ------ 3 files changed, 211 insertions(+), 118 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index a718963..228a756 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -357,12 +357,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 --backe= nd=3D$(TRACE_BACKEND) -h < $< > $@," GEN trace.h") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --forma= t=3Dh --backend=3D$(TRACE_BACKEND) < $< > $@," GEN trace.h") @cmp -s $@ trace.h || cp $@ trace.h =20 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 --backe= nd=3D$(TRACE_BACKEND) -c < $< > $@," GEN trace.c") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --forma= t=3Dc --backend=3D$(TRACE_BACKEND) < $< > $@," GEN trace.c") @cmp -s $@ trace.c || cp $@ trace.c =20 trace.o: trace.c $(GENERATED_HEADERS) @@ -375,7 +375,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)/con= fig-host.mak - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --backe= nd=3D$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --forma= t=3Dd --backend=3D$(TRACE_BACKEND) < $< > $@," GEN trace-dtrace.dtrace= ") @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace =20 trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS) diff --git a/Makefile.target b/Makefile.target index 3e42e5a..c1e58fb 100644 --- a/Makefile.target +++ b/Makefile.target @@ -60,11 +60,12 @@ endif =20 $(QEMU_PROG).stp: $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py \ + --format=3Dstap \ --backend=3D$(TRACE_BACKEND) \ --binary=3D$(bindir)/$(QEMU_PROG) \ --target-arch=3D$(TARGET_ARCH) \ --target-type=3D$(TARGET_TYPE) \ - --stap < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_P= ROG).stp") + < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).st= p") else stap: endif diff --git a/scripts/tracetool.py b/scripts/tracetool.py index 377c683..6ef4374 100755 --- a/scripts/tracetool.py +++ b/scripts/tracetool.py @@ -12,33 +12,107 @@ import sys import getopt import re =20 -def usage(): - print "Tracetool: Generate tracing code for trace events file on std= in" - print "Usage:" - print sys.argv[0], "--backend=3D[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 =20 -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) +class _Tag: + pass + +_formats =3D {} + +BEGIN =3D _Tag() +END =3D _Tag() +_DESCR =3D _Tag() + +def for_format(format_, when, descr =3D 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_] =3D {} + if descr is not None: + if _DESCR in _formats[format_]: + raise ValueError("Description already set") + _formats[format_][_DESCR] =3D descr + + def func(f): + _formats[format_][when] =3D 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 "" =20 + + +###################################################################### +# backend auto-registration and format compatibility + +_backends =3D {} + +def for_backend(backend, format_, descr =3D None): + if backend not in _backends: + _backends[backend] =3D {} + 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] =3D descr + + def func(f): + _backends[backend][format_] =3D 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): =20 #include "qemu-common.h"''' =20 +@for_format("h", END) def trace_h_end(events): print '#endif /* TRACE_H */' =20 + +################################################## +# format: c + +@for_format("c", BEGIN, "Generate .c file") def trace_c_begin(events): print '/* This file is autogenerated by tracetool, do not edit. */' =20 + + +###################################################################### +# 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 =20 +@for_backend("nop", "c") def nop_c(events): pass # nop, reqd for converters =20 +################################################## +# 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];' =20 =20 +@for_backend("simple", "c") def simple_c(events): print '#include "trace.h"' print @@ -108,6 +202,10 @@ def simple_c(events): print print '};' =20 +################################################## +# backend: stderr + +@for_backend("stderr", "h", "Stderr built-in backend") def stderr_h(events): print '''#include #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) =20 +@for_backend("stderr", "c") def stderr_c(events): print '''#include "trace.h" =20 @@ -145,6 +244,11 @@ TraceEvent trace_list[] =3D { print print '};' =20 + +################################################## +# backend: ust + +@for_backend("ust", "h", "LTTng User Space Tracing backend") def ust_h(events): print '''#include #undef mutex_lock @@ -169,6 +273,7 @@ _DECLARE_TRACEPOINT_NOARGS(ust_%(name)s); } print =20 +@for_backend("ust", "c") def ust_c(events): print '''#include #undef mutex_lock @@ -214,6 +319,10 @@ static void __attribute__((constructor)) trace_init(= void) } print '}' =20 +################################################## +# 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()), } =20 +@for_backend("dtrace", "c") def dtrace_c(events): pass # No need for function definitions in dtrace backend =20 +@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 '};' =20 +@for_backend("nop", "d") def dtrace_nop_d(events): pass =20 + +@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,10 @@ probe %(probeprefix)s.%(name)s =3D process("%(binar= y)s").mark("%(name)s") def dtrace_nop_stp(events): pass =20 -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 =3D { - '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 =3D { - 'h': { - 'begin': trace_h_begin, - 'end': trace_h_end, - }, - 'c': { - 'begin': trace_c_begin, - }, - 'd': { - 'begin': trace_d_begin, - }, - 'stap': { - 'begin': trace_stap_begin, - }, -} =20 +###################################################################### # Event arguments + class Arguments: def __init__ (self, arg_str): self._args =3D [] @@ -369,7 +436,10 @@ class Arguments: def types(self): return [ type_ for type_, _ in self._args ] =20 + +###################################################################### # A trace event + cre =3D re.compile("((?P.*)\s+)?(?P[^(\s]+)\((?P[^)]*= )\)\s*(?P\".*)?") =20 VALID_PROPS =3D set(["disable"]) @@ -399,32 +469,51 @@ def read_events(fobj): res.append(Event(line)) return res =20 +###################################################################### +# Main + +format_ =3D "" binary =3D "" probeprefix =3D "" =20 +def usage(): + print "Tracetool: Generate tracing code for trace events file on std= in" + print "Usage:" + print sys.argv[0], " --format=3D --backend=3D" + 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 =3D "" targetarch =3D "" - supported_backends =3D ["simple", "nop", "stderr", "dtrace", "ust"] - short_options =3D "hcd" - long_options =3D ["stap", "backend=3D", "binary=3D", "target-arch=3D= ", "target-type=3D", "probe-prefix=3D", "list-backends", "check-backend"] + long_options =3D ["format=3D", "backend=3D", "binary=3D", "target-ar= ch=3D", "target-type=3D", "probe-prefix=3D", "list-backends", "check-back= end"] try: - opts, args =3D getopt.getopt(sys.argv[1:], short_options, long_o= ptions) + opts, args =3D 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 recogn= ized" usage() sys.exit(2) for opt, arg in opts: - if opt =3D=3D '-h': - output =3D 'h' - elif opt =3D=3D '-c': - output =3D 'c' - elif opt =3D=3D '-d': - output =3D 'd' - elif opt =3D=3D '--stap': - output =3D 'stap' + if opt =3D=3D '--format': + format_ =3D arg elif opt =3D=3D '--backend': backend =3D arg elif opt =3D=3D '--binary': @@ -436,30 +525,27 @@ def main(): elif opt =3D=3D '--probe-prefix': probeprefix =3D arg elif opt =3D=3D '--list-backends': - print 'simple, nop, stderr, dtrace, ust' + print ', '.join(_backends) sys.exit(0) elif opt =3D=3D "--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() =20 - if backend =3D=3D "" or output =3D=3D "": + 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 !=3D 'dtrace' and output =3D=3D 'd': - print 'DTrace probe generator not applicable to %s backend' % ba= ckend - sys.exit(1) =20 - if output =3D=3D 'stap': - if backend !=3D "dtrace": - print 'SystemTAP tapset generator not applicable to %s backe= nd' % backend - sys.exit(1) + if format_ =3D=3D 'stap': if binary =3D=3D "": print '--binary is required for SystemTAP tapset generator' sys.exit(1) @@ -474,12 +560,18 @@ def main(): =20 events =3D read_events(sys.stdin) =20 - 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.prop= erties ]) - if 'end' in formats[output]: - formats[output]['end'](events) + try: + # just force format/backend compatibility check + bfun =3D get_backend(format_, backend) + bnop =3D 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) =20 if __name__ =3D=3D "__main__": main()