From patchwork Thu Mar 1 13:25:35 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Harsh Prateek Bora X-Patchwork-Id: 144024 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 142FE1007D2 for ; Fri, 2 Mar 2012 01:28:15 +1100 (EST) Received: from localhost ([::1]:54601 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S362P-0005ZY-NC for incoming@patchwork.ozlabs.org; Thu, 01 Mar 2012 08:27:17 -0500 Received: from eggs.gnu.org ([208.118.235.92]:51177) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S361Y-00037L-72 for qemu-devel@nongnu.org; Thu, 01 Mar 2012 08:26:34 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S3614-0000Uu-FQ for qemu-devel@nongnu.org; Thu, 01 Mar 2012 08:26:23 -0500 Received: from e28smtp08.in.ibm.com ([122.248.162.8]:43794) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S3613-0000RS-IA for qemu-devel@nongnu.org; Thu, 01 Mar 2012 08:25:54 -0500 Received: from /spool/local by e28smtp08.in.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 1 Mar 2012 18:55:47 +0530 Received: from d28relay02.in.ibm.com (9.184.220.59) by e28smtp08.in.ibm.com (192.168.1.138) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 1 Mar 2012 18:55:43 +0530 Received: from d28av02.in.ibm.com (d28av02.in.ibm.com [9.184.220.64]) by d28relay02.in.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q21DPgi63567664 for ; Thu, 1 Mar 2012 18:55:42 +0530 Received: from d28av02.in.ibm.com (loopback [127.0.0.1]) by d28av02.in.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q21DPfL0013236 for ; Fri, 2 Mar 2012 00:25:42 +1100 Received: from harshbora.in.ibm.com ([9.124.35.242]) by d28av02.in.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q21DPfJn013178; Fri, 2 Mar 2012 00:25:41 +1100 From: Harsh Prateek Bora To: qemu-devel@nongnu.org Date: Thu, 1 Mar 2012 18:55:35 +0530 Message-Id: <1330608340-9515-10-git-send-email-harsh@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.1.1 In-Reply-To: <1330608340-9515-1-git-send-email-harsh@linux.vnet.ibm.com> References: <1330608340-9515-1-git-send-email-harsh@linux.vnet.ibm.com> MIME-Version: 1.0 x-cbid: 12030113-2000-0000-0000-0000069AA618 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 122.248.162.8 Cc: stefanha@gmail.com, vilanova@ac.upc.edu, aneesh.kumar@linux.vnet.ibm.com Subject: [Qemu-devel] [RFC PATCH v5 09/14] trace: [tracetool] Automatically establish available backends and formats X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Lluís Vilanova Signed-off-by: Lluís Vilanova Signed-off-by: Harsh Prateek Bora --- 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 #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 #undef mutex_lock @@ -169,6 +273,7 @@ _DECLARE_TRACEPOINT_NOARGS(ust_%(name)s); } print +@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 '}' +################################################## +# 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.*)\s+)?(?P[^(\s]+)\((?P[^)]*)\)\s*(?P\".*)?") 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= --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()