From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:52056) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SCYAC-00075q-Oj for qemu-devel@nongnu.org; Tue, 27 Mar 2012 11:18:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SCYA3-0004NW-O3 for qemu-devel@nongnu.org; Tue, 27 Mar 2012 11:18:24 -0400 Received: from mx1.redhat.com ([209.132.183.28]:29116) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SCYA3-0004Mo-9S for qemu-devel@nongnu.org; Tue, 27 Mar 2012 11:18:15 -0400 Date: Tue, 27 Mar 2012 17:17:56 +0200 From: Alon Levy Message-ID: <20120327151756.GK32389@garlic> References: <20120326173743.20814.3629.stgit@ginnungagap.bsc.es> <20120326173750.20814.75373.stgit@ginnungagap.bsc.es> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline In-Reply-To: <20120326173750.20814.75373.stgit@ginnungagap.bsc.es> Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [RFC PATCH v2 1/8] tracetool: Rewrite infrastructure as python modules List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: =?iso-8859-1?Q?Llu=EDs?= Vilanova Cc: stefanha@gmail.com, qemu-devel@nongnu.org On Mon, Mar 26, 2012 at 07:37:50PM +0200, Llu=EDs Vilanova wrote: > Signed-off-by: Llu=EDs Vilanova Hi, Some comments inline. Alon > --- > Makefile.objs | 6=20 > Makefile.target | 13 - > configure | 4=20 > scripts/tracetool | 648 -------------------------= -------- > scripts/tracetool.py | 110 ++++++ > scripts/tracetool/__init__.py | 205 ++++++++++ > scripts/tracetool/backend/__init__.py | 114 ++++++ > scripts/tracetool/format/__init__.py | 91 +++++ > 8 files changed, 532 insertions(+), 659 deletions(-) > delete mode 100755 scripts/tracetool > create mode 100755 scripts/tracetool.py > create mode 100644 scripts/tracetool/__init__.py > create mode 100644 scripts/tracetool/backend/__init__.py > create mode 100644 scripts/tracetool/format/__init__.py >=20 > diff --git a/Makefile.objs b/Makefile.objs > index 226b01d..8e56f48 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -373,12 +373,12 @@ else > trace.h: trace.h-timestamp > endif > trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.m= ak > - $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKE= ND) -h < $< > $@," GEN trace.h") > + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --for= mat=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.m= ak > - $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKE= ND) -c < $< > $@," GEN trace.c") > + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --for= mat=3Dc --backend=3D$(TRACE_BACKEND) < $< > $@," GEN trace.c") > @cmp -s $@ trace.c || cp $@ trace.c > =20 > trace.o: trace.c $(GENERATED_HEADERS) > @@ -391,7 +391,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)/c= onfig-host.mak > - $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKE= ND) -d < $< > $@," GEN trace-dtrace.dtrace") > + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --for= mat=3Dd --backend=3D$(TRACE_BACKEND) < $< > $@," GEN trace-dtrace.dtra= ce") > @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 63cf769..fe28e8b 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -59,12 +59,13 @@ TARGET_TYPE=3Dsystem > endif > =20 > $(QEMU_PROG).stp: > - $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool \ > - --$(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") > + $(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) \ > + < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).= stp") > else > stap: > endif > diff --git a/configure b/configure > index 8b4e3c1..c2d6117 100755 > --- a/configure > +++ b/configure > @@ -1097,7 +1097,7 @@ echo " --disable-docs disable document= ation build" > echo " --disable-vhost-net disable vhost-net acceleration suppor= t" > echo " --enable-vhost-net enable vhost-net acceleration support= " > echo " --enable-trace-backend=3DB Set trace backend" > -echo " Available backends:" $("$source_path"= /scripts/tracetool --list-backends) > +echo " Available backends:" $($python "$sour= ce_path"/scripts/tracetool.py --list-backends) > echo " --with-trace-file=3DNAME Full PATH,NAME of file to store tra= ces" > echo " Default:trace-" > echo " --disable-spice disable spice" > @@ -2654,7 +2654,7 @@ fi > ########################################## > # check if trace backend exists > =20 > -sh "$source_path/scripts/tracetool" "--$trace_backend" --check-backend= > /dev/null 2> /dev/null > +$python "$source_path/scripts/tracetool.py" "--backend=3D$trace_backen= d" --check-backend > /dev/null 2> /dev/null > if test "$?" -ne 0 ; then > echo > echo "Error: invalid trace backend" > diff --git a/scripts/tracetool b/scripts/tracetool > deleted file mode 100755 > index 65bd0a1..0000000 > --- a/scripts/tracetool > +++ /dev/null > @@ -1,648 +0,0 @@ > -#!/bin/sh > -# > -# Code generator for trace events > -# > -# Copyright IBM, Corp. 2010 > -# > -# This work is licensed under the terms of the GNU GPL, version 2. Se= e > -# the COPYING file in the top-level directory. > - > -# Disable pathname expansion, makes processing text with '*' character= s simpler > -set -f > - > -usage() > -{ > - cat >&2 < -usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c] > -Generate tracing code for a file on stdin. > - > -Backends: > - --nop Tracing disabled > - --simple Simple built-in backend > - --stderr Stderr built-in backend > - --ust LTTng User Space Tracing backend > - --dtrace DTrace/SystemTAP 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) > - > -Options: > - --binary [path] Full path to QEMU binary > - --target-arch [arch] QEMU emulator target arch > - --target-type [type] QEMU emulator target type ('system' or 'use= r') > - --probe-prefix [prefix] Prefix for dtrace probe names > - (default: qemu-\$targettype-\$targetarch) > - > -EOF > - exit 1 > -} > - > -# Print a line without interpreting backslash escapes > -# > -# The built-in echo command may interpret backslash escapes without an= option > -# to disable this behavior. > -puts() > -{ > - printf "%s\n" "$1" > -} > - > -# Get the name of a trace event > -get_name() > -{ > - local name > - name=3D${1%%\(*} > - echo "${name##* }" > -} > - > -# Get the given property of a trace event > -# 1: trace-events line > -# 2: property name > -# -> return 0 if property is present, or 1 otherwise > -has_property() > -{ > - local props prop > - props=3D${1%%\(*} > - props=3D${props% *} > - for prop in $props; do > - if [ "$prop" =3D "$2" ]; then > - return 0 > - fi > - done > - return 1 > -} > - > -# Get the argument list of a trace event, including types and names > -get_args() > -{ > - local args > - args=3D${1#*\(} > - args=3D${args%%\)*} > - echo "$args" > -} > - > -# Get the argument name list of a trace event > -get_argnames() > -{ > - local nfields field name sep > - nfields=3D0 > - sep=3D"$2" > - for field in $(get_args "$1"); do > - nfields=3D$((nfields + 1)) > - > - # Drop pointer star > - field=3D${field#\*} > - > - # Only argument names have commas at the end > - name=3D${field%,} > - test "$field" =3D "$name" && continue > - > - printf "%s%s " $name $sep > - done > - > - # Last argument name > - if [ "$nfields" -gt 1 ] > - then > - printf "%s" "$name" > - fi > -} > - > -# Get the number of arguments to a trace event > -get_argc() > -{ > - local name argc > - argc=3D0 > - for name in $(get_argnames "$1", ","); do > - argc=3D$((argc + 1)) > - done > - echo $argc > -} > - > -# Get the format string including double quotes for a trace event > -get_fmt() > -{ > - puts "${1#*)}" > -} > - > -linetoh_begin_nop() > -{ > - return > -} > - > -linetoh_nop() > -{ > - local name args > - name=3D$(get_name "$1") > - args=3D$(get_args "$1") > - > - # Define an empty function for the trace event > - cat < -static inline void trace_$name($args) > -{ > -} > -EOF > -} > - > -linetoh_end_nop() > -{ > - return > -} > - > -linetoc_begin_nop() > -{ > - return > -} > - > -linetoc_nop() > -{ > - # No need for function definitions in nop backend > - return > -} > - > -linetoc_end_nop() > -{ > - return > -} > - > -linetoh_begin_simple() > -{ > - cat < -#include "trace/simple.h" > -EOF > - > - simple_event_num=3D0 > -} > - > -cast_args_to_uint64_t() > -{ > - local arg > - for arg in $(get_argnames "$1", ","); do > - printf "%s" "(uint64_t)(uintptr_t)$arg" > - done > -} > - > -linetoh_simple() > -{ > - local name args argc trace_args > - name=3D$(get_name "$1") > - args=3D$(get_args "$1") > - argc=3D$(get_argc "$1") > - > - trace_args=3D"$simple_event_num" > - if [ "$argc" -gt 0 ] > - then > - trace_args=3D"$trace_args, $(cast_args_to_uint64_t "$1")" > - fi > - > - cat < -static inline void trace_$name($args) > -{ > - trace$argc($trace_args); > -} > -EOF > - > - simple_event_num=3D$((simple_event_num + 1)) > -} > - > -linetoh_end_simple() > -{ > - cat < -#define NR_TRACE_EVENTS $simple_event_num > -extern TraceEvent trace_list[NR_TRACE_EVENTS]; > -EOF > -} > - > -linetoc_begin_simple() > -{ > - cat < -#include "trace.h" > - > -TraceEvent trace_list[] =3D { > -EOF > - simple_event_num=3D0 > - > -} > - > -linetoc_simple() > -{ > - local name > - name=3D$(get_name "$1") > - cat < -{.tp_name =3D "$name", .state=3D0}, > -EOF > - simple_event_num=3D$((simple_event_num + 1)) > -} > - > -linetoc_end_simple() > -{ > - cat < -}; > -EOF > -} > - > -#STDERR > -linetoh_begin_stderr() > -{ > - cat < -#include > -#include "trace/stderr.h" > - > -extern TraceEvent trace_list[]; > -EOF > - > - stderr_event_num=3D0 > -} > - > -linetoh_stderr() > -{ > - local name args argnames argc fmt > - name=3D$(get_name "$1") > - args=3D$(get_args "$1") > - argnames=3D$(get_argnames "$1" ",") > - argc=3D$(get_argc "$1") > - fmt=3D$(get_fmt "$1") > - > - if [ "$argc" -gt 0 ]; then > - argnames=3D", $argnames" > - fi > - > - cat < -static inline void trace_$name($args) > -{ > - if (trace_list[$stderr_event_num].state !=3D 0) { > - fprintf(stderr, "$name " $fmt "\n" $argnames); > - } > -} > -EOF > - stderr_event_num=3D$((stderr_event_num + 1)) > - > -} > - > -linetoh_end_stderr() > -{ > - cat < -#define NR_TRACE_EVENTS $stderr_event_num > -EOF > -} > - > -linetoc_begin_stderr() > -{ > - cat < -#include "trace.h" > - > -TraceEvent trace_list[] =3D { > -EOF > - stderr_event_num=3D0 > -} > - > -linetoc_stderr() > -{ > - local name > - name=3D$(get_name "$1") > - cat < -{.tp_name =3D "$name", .state=3D0}, > -EOF > - stderr_event_num=3D$(($stderr_event_num + 1)) > -} > - > -linetoc_end_stderr() > -{ > - cat < -}; > -EOF > -} > -#END OF STDERR > - > -# Clean up after UST headers which pollute the namespace > -ust_clean_namespace() { > - cat < -#undef mutex_lock > -#undef mutex_unlock > -#undef inline > -#undef wmb > -EOF > -} > - > -linetoh_begin_ust() > -{ > - echo "#include " > - ust_clean_namespace > -} > - > -linetoh_ust() > -{ > - local name args argnames > - name=3D$(get_name "$1") > - args=3D$(get_args "$1") > - argnames=3D$(get_argnames "$1", ",") > - > - cat < -DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames)); > -#define trace_$name trace_ust_$name > -EOF > -} > - > -linetoh_end_ust() > -{ > - return > -} > - > -linetoc_begin_ust() > -{ > - cat < -#include > -$(ust_clean_namespace) > -#include "trace.h" > -EOF > -} > - > -linetoc_ust() > -{ > - local name args argnames fmt > - name=3D$(get_name "$1") > - args=3D$(get_args "$1") > - argnames=3D$(get_argnames "$1", ",") > - [ -z "$argnames" ] || argnames=3D", $argnames" > - fmt=3D$(get_fmt "$1") > - > - cat < -DEFINE_TRACE(ust_$name); > - > -static void ust_${name}_probe($args) > -{ > - trace_mark(ust, $name, $fmt$argnames); > -} > -EOF > - > - # Collect names for later > - names=3D"$names $name" > -} > - > -linetoc_end_ust() > -{ > - cat < -static void __attribute__((constructor)) trace_init(void) > -{ > -EOF > - > - for name in $names; do > - cat < - register_trace_ust_$name(ust_${name}_probe); > -EOF > - done > - > - echo "}" > -} > - > -linetoh_begin_dtrace() > -{ > - cat < -#include "trace-dtrace.h" > -EOF > -} > - > -linetoh_dtrace() > -{ > - local name args argnames nameupper > - name=3D$(get_name "$1") > - args=3D$(get_args "$1") > - argnames=3D$(get_argnames "$1", ",") > - > - nameupper=3D`echo $name | tr '[:lower:]' '[:upper:]'` > - > - # Define an empty function for the trace event > - cat < -static inline void trace_$name($args) { > - QEMU_${nameupper}($argnames); > -} > -EOF > -} > - > -linetoh_end_dtrace() > -{ > - return > -} > - > -linetoc_begin_dtrace() > -{ > - return > -} > - > -linetoc_dtrace() > -{ > - # No need for function definitions in dtrace backend > - return > -} > - > -linetoc_end_dtrace() > -{ > - return > -} > - > -linetod_begin_dtrace() > -{ > - cat < -provider qemu { > -EOF > -} > - > -linetod_dtrace() > -{ > - local name args > - name=3D$(get_name "$1") > - args=3D$(get_args "$1") > - > - # DTrace provider syntax expects foo() for empty > - # params, not foo(void) > - if [ "$args" =3D "void" ]; then > - args=3D"" > - fi > - > - # Define prototype for probe arguments > - cat < - probe $name($args); > -EOF > -} > - > -linetod_end_dtrace() > -{ > - cat < -}; > -EOF > -} > - > -linetostap_begin_dtrace() > -{ > - return > -} > - > -linetostap_dtrace() > -{ > - local i arg name args arglist > - name=3D$(get_name "$1") > - args=3D$(get_args "$1") > - arglist=3D$(get_argnames "$1", "") > - > - # Define prototype for probe arguments > - cat < -probe $probeprefix.$name =3D process("$binary").mark("$name") > -{ > -EOF > - > - i=3D1 > - for arg in $arglist > - do > - # 'limit' is a reserved keyword > - if [ "$arg" =3D "limit" ]; then > - arg=3D"_limit" > - fi > - cat < - $arg =3D \$arg$i; > -EOF > - i=3D"$((i+1))" > - done > - > - cat < -} > -EOF > -} > - > -linetostap_end_dtrace() > -{ > - return > -} > - > -# Process stdin by calling begin, line, and end functions for the back= end > -convert() > -{ > - local begin process_line end str name NAME enabled > - begin=3D"lineto$1_begin_$backend" > - process_line=3D"lineto$1_$backend" > - end=3D"lineto$1_end_$backend" > - > - "$begin" > - > - while read -r str; do > - # Skip comments and empty lines > - test -z "${str%%#*}" && continue > - > - echo > - # Process the line. The nop backend handles disabled lines. > - if has_property "$str" "disable"; then > - "lineto$1_nop" "$str" > - enabled=3D0 > - else > - "$process_line" "$str" > - enabled=3D1 > - fi > - if [ "$1" =3D "h" ]; then > - name=3D$(get_name "$str") > - NAME=3D$(echo $name | tr '[:lower:]' '[:upper:]') > - echo "#define TRACE_${NAME}_ENABLED ${enabled}" > - fi > - done > - > - echo > - "$end" > -} > - > -tracetoh() > -{ > - cat < -#ifndef TRACE_H > -#define TRACE_H > - > -/* This file is autogenerated by tracetool, do not edit. */ > - > -#include "qemu-common.h" > -EOF > - convert h > - echo "#endif /* TRACE_H */" > -} > - > -tracetoc() > -{ > - echo "/* This file is autogenerated by tracetool, do not edit. */" > - convert c > -} > - > -tracetod() > -{ > - if [ $backend !=3D "dtrace" ]; then > - echo "DTrace probe generator not applicable to $backend backend= " > - exit 1 > - fi > - echo "/* This file is autogenerated by tracetool, do not edit. */" > - convert d > -} > - > -tracetostap() > -{ > - if [ $backend !=3D "dtrace" ]; then > - echo "SystemTAP tapset generator not applicable to $backend bac= kend" > - exit 1 > - fi > - if [ -z "$binary" ]; then > - echo "--binary is required for SystemTAP tapset generator" > - exit 1 > - fi > - if [ -z "$probeprefix" -a -z "$targettype" ]; then > - echo "--target-type is required for SystemTAP tapset generator" > - exit 1 > - fi > - if [ -z "$probeprefix" -a -z "$targetarch" ]; then > - echo "--target-arch is required for SystemTAP tapset generator" > - exit 1 > - fi > - if [ -z "$probeprefix" ]; then > - probeprefix=3D"qemu.$targettype.$targetarch"; > - fi > - echo "/* This file is autogenerated by tracetool, do not edit. */" > - convert stap > -} > - > - > -backend=3D > -output=3D > -binary=3D > -targettype=3D > -targetarch=3D > -probeprefix=3D > - > - > -until [ -z "$1" ] > -do > - case "$1" in > - "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend=3D= "${1#--}" ;; > - > - "--binary") shift ; binary=3D"$1" ;; > - "--target-arch") shift ; targetarch=3D"$1" ;; > - "--target-type") shift ; targettype=3D"$1" ;; > - "--probe-prefix") shift ; probeprefix=3D"$1" ;; > - > - "-h" | "-c" | "-d") output=3D"${1#-}" ;; > - "--stap") output=3D"${1#--}" ;; > - > - "--check-backend") exit 0 ;; # used by ./configure to test for bac= kend > - > - "--list-backends") # used by ./configure to list available backend= s > - echo "nop simple stderr ust dtrace" > - exit 0 > - ;; > - > - *) > - usage;; > - esac > - shift > -done > - > -if [ "$backend" =3D "" -o "$output" =3D "" ]; then > - usage > -fi > - > -gen=3D"traceto$output" > -"$gen" > - > -exit 0 > diff --git a/scripts/tracetool.py b/scripts/tracetool.py > new file mode 100755 > index 0000000..22623ae > --- /dev/null > +++ b/scripts/tracetool.py > @@ -0,0 +1,110 @@ > +#!/usr/bin/env python > +# -*- coding: utf-8 -*- > + > +""" > +Foo. Real docstring missing. > +""" > + > +__author__ =3D "Llu=EDs Vilanova " > +__copyright__ =3D "Copyright 2012, Llu=EDs Vilanova " > +__license__ =3D "GPL version 2 or (at your option) any later versio= n" > + > +__maintainer__ =3D "Stefan Hajnoczi" > +__email__ =3D "stefanha@linux.vnet.ibm.com" > + > + > +import sys > +import getopt > + > +from tracetool import error_write, out > +import tracetool.backend > +import tracetool.format > + > + > +_SCRIPT =3D "" I don't understand the point of this, why not use sys.argv[0] directly? > + > +def error_opt(msg =3D None): > + if msg is not None: > + error_write("Error: " + msg + "\n") > + > + backend_descr =3D "\n".join([ " %-15s %s" % (n, d) > + for n,d in tracetool.backend.get_list(= ) ]) > + format_descr =3D "\n".join([ " %-15s %s" % (n, d) > + for n,d in tracetool.format.get_list() = ]) > + error_write("""\ > +Usage: %(script)s --format=3D --backend=3D [= ] > + > +Backends: > +%(backends)s > + > +Formats: > +%(formats)s > + > +Options: > + --help This help message. > + --list-backends Print list of available backends. > + --check-backend Check if the given backend is valid. > +""" % { > + "script" : _SCRIPT, > + "backends" : backend_descr, > + "formats" : format_descr, > + }) > + > + if msg is None: > + sys.exit(0) > + else: > + sys.exit(1) > + > + > +def main(args): > + global _SCRIPT > + _SCRIPT =3D sys.argv[0] > + > + long_opts =3D [ "backend=3D", "format=3D", "help", "list-backends= ", "check-backend" ] > + long_opts +=3D [ "binary=3D", "target-type=3D", "target-arch=3D", = "probe-prefix=3D" ] > + > + try: > + opts, args =3D getopt.getopt(args[1:], "", long_opts) > + except getopt.GetoptError as err: > + error_opt(str(err)) > + > + check_backend =3D False > + arg_backend =3D "" > + arg_format =3D "" > + for opt, arg in opts: > + if opt =3D=3D "--help": > + error_opt() > + > + elif opt =3D=3D "--backend": > + arg_backend =3D arg > + elif opt =3D=3D "--format": > + arg_format =3D arg > + > + elif opt =3D=3D "--list-backends": > + public_backends =3D tracetool.backend.get_list(only_public= =3D True) > + out(", ".join([ b for b,_ in public_backends ])) > + sys.exit(0) > + elif opt =3D=3D "--check-backend": > + check_backend =3D True > + > + else: > + error_opt("unhandled option: %s" % opt) > + > + if arg_backend is None: > + error_opt("backend not set") > + > + if check_backend: > + if tracetool.backend.exists(arg_backend): > + sys.exit(0) > + else: > + sys.exit(1) > + > + kwargs =3D {} > + > + try: > + tracetool.generate(sys.stdin, arg_format, arg_backend, **kwarg= s) > + except tracetool.TracetoolError as e: > + error_opt(str(e)) > + > +if __name__ =3D=3D "__main__": > + main(sys.argv) > diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__= .py > new file mode 100644 > index 0000000..d8e5cdd > --- /dev/null > +++ b/scripts/tracetool/__init__.py > @@ -0,0 +1,205 @@ > +#!/usr/bin/env python > +# -*- coding: utf-8 -*- > + > +""" > +Machinery for generating tracing-related intermediate files. > +""" > + > +__author__ =3D "Llu=EDs Vilanova " > +__copyright__ =3D "Copyright 2012, Llu=EDs Vilanova " > +__license__ =3D "GPL version 2 or (at your option) any later versio= n" > + > +__maintainer__ =3D "Stefan Hajnoczi" > +__email__ =3D "stefanha@linux.vnet.ibm.com" > + > + > +import re > +import sys > + > +import tracetool.format > +import tracetool.backend > + > + > +def error_write(*lines): > + """Write a set of error lines.""" > + sys.stderr.writelines("\n".join(lines) + "\n") > + > +def error(*lines): > + """Write a set of error lines and exit.""" > + error_write(*lines) > + sys.exit(1) > + > + > +def out(*lines): > + """Write a set of output lines.""" > + sys.stdout.writelines("\n".join(lines) + "\n") > + > + > +class Arguments: > + """Event arguments description. > + > + Parameters > + ---------- > + arg_str : str > + String describing the event arguments. > + """ > + > + def __init__ (self, arg_str): > + self._args =3D [] > + for arg in arg_str.split(","): > + arg =3D arg.strip() > + parts =3D arg.split() > + head, sep, tail =3D parts[-1].rpartition("*") > + parts =3D parts[:-1] > + if tail =3D=3D "void": > + assert len(parts) =3D=3D 0 and sep =3D=3D "" > + continue > + arg_type =3D " ".join(parts + [ " ".join([head, sep]).stri= p() ]).strip() > + self._args.append((arg_type, tail)) > + > + def __iter__(self): > + """Iterate over the (type, name) pairs.""" > + return iter(self._args) > + > + def __len__(self): > + """Number of arguments.""" > + return len(self._args) > + > + def __str__(self): > + """String suitable for declaring function arguments.""" > + if len(self._args) =3D=3D 0: > + return "void" > + else: > + return ", ".join([ " ".join([t, n]) for t,n in self._args = ]) > + > + def names(self): > + """List of argument names.""" > + return [ name for _, name in self._args ] > + > + def types(self): > + """List of argument types.""" > + return [ type_ for type_, _ in self._args ] > + > + > +class Event(object): > + """Event description. > + > + Parameters > + ---------- > + line : str > + Line describing the event. > + > + Attributes > + ---------- > + name : str > + The event name. > + fmt : str > + The event format string. > + properties : set(str) > + Properties of the event. > + args : Arguments > + The event arguments. > + """ > + > + _CRE =3D re.compile("((?P.*)\s+)?(?P[^(\s]+)\((?P[^)]*)\)\s*(?P\".*)?") > + > + _VALID_PROPS =3D set(["disable"]) > + > + def __init__(self, line): > + m =3D self._CRE.match(line) > + assert m is not None > + groups =3D m.groupdict('') > + self.name =3D groups["name"] > + self.fmt =3D groups["fmt"] > + self.properties =3D groups["props"].split() > + self.args =3D Arguments(groups["args"]) > + > + unknown_props =3D set(self.properties) - self._VALID_PROPS > + if len(unknown_props) > 0: > + raise ValueError("Unknown properties: %s" % ", ".join(unkn= own_props)) > + > + > +def _read_events(fobj): > + res =3D [] > + for line in fobj: > + if not line.strip(): > + continue > + if line.lstrip().startswith('#'): > + continue Tab got in. > + res.append(Event(line)) > + return res > + > + > +class TracetoolError (Exception): > + """Exception for calls to generate.""" > + pass > + > + > +def try_import(mod_name, attr_name =3D None, attr_default =3D None): > + """Try to import a module and get an attribute from it. > + > + Parameters > + ---------- > + mod_name : str > + Module name. > + attr_name : str, optional > + Name of an attribute in the module. > + attr_default : optional > + Default value if the attribute does not exist in the module. > + > + Returns > + ------- > + A pair indicating whether the module could be imported and the mod= ule or > + object or attribute value. > + """ > + mod_name =3D mod_name.replace("-", "_") > + try: > + module =3D __import__(mod_name, fromlist=3D["__package__"]) > + if attr_name is None: > + return True, module > + return True, getattr(module, str(attr_name), attr_default) > + except ImportError: > + return False, None > + > + > +def generate(fevents, format, backend, **options): > + """Generate the output for the given (format, backend) pair.""" > + # fix strange python error (UnboundLocalError tracetool) > + import tracetool > + > + if len(options) > 0: > + raise ValueError("unknown options: " + ", ".join(options)) > + > + format =3D str(format) > + if len(format) is 0: > + raise TracetoolError("format not set") > + mformat =3D format.replace("-", "_") > + if not tracetool.format.exists(mformat): > + raise TracetoolError("unknown format: %s" % format) > + > + backend =3D str(backend) > + if len(backend) is 0: > + raise TracetoolError("backend not set") > + mbackend =3D backend.replace("-", "_") > + if not tracetool.backend.exists(mbackend): > + raise TracetoolError("unknown backend: %s" % backend) > + > + if not tracetool.backend.compatible(mbackend, mformat): > + raise TracetoolError("backend '%s' not compatible with format = '%s'" % > + (backend, format)) > + > + events =3D _read_events(fevents) > + > + if backend =3D=3D "nop": > + ( e.properies.add("disable") for e in events ) > + > + tracetool.format.generate_begin(mformat, events) > + tracetool.backend.generate("nop", format, > + [ e > + for e in events > + if "disable" in e.properties ]) > + tracetool.backend.generate(backend, format, > + [ e > + for e in events > + if "disable" not in e.properties ]) > + tracetool.format.generate_end(mformat, events) > diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/= backend/__init__.py > new file mode 100644 > index 0000000..23cad9f > --- /dev/null > +++ b/scripts/tracetool/backend/__init__.py > @@ -0,0 +1,114 @@ > +#!/usr/bin/env python > +# -*- coding: utf-8 -*- > + > +""" > +Backend management. > + > + > +Creating new backends > +--------------------- > + > +A new backend named 'foo-bar' corresponds to Python module > +'tracetool/backend/foo_bar.py'. > + > +A backend module should provide a docstring, whose first non-empty lin= e will be > +considered its short description. > + > +All backends must generate their contents through the 'tracetool.out' = routine. > + > + > +Backend attributes > +------------------ > + > +=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > +Attribute Description > +=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > +PUBLIC If exists and is set to 'True', the backend is considered "p= ublic". > +=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > + > + > +Backend functions > +----------------- > + > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > +Function Description > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > + Called to generate the format- and backend-specific code for = each of > + the specified events. If the function does not exist, the bac= kend is > + considered not compatible with the given format. > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > +""" > + > +__author__ =3D "Llu=EDs Vilanova " > +__copyright__ =3D "Copyright 2012, Llu=EDs Vilanova " > +__license__ =3D "GPL version 2 or (at your option) any later versio= n" > + > +__maintainer__ =3D "Stefan Hajnoczi" > +__email__ =3D "stefanha@linux.vnet.ibm.com" > + > + > +import pkgutil > + > +import tracetool > + > + > +def get_list(only_public =3D False): > + """Get a list of (name, description) pairs.""" > + res =3D [("nop", "Tracing disabled.")] > + for _, modname, _ in pkgutil.iter_modules(tracetool.backend.__path= __): > + module =3D tracetool.try_import("tracetool.backend." + modname= )[1] > + Here module can be None if ImportError was raised in try_import. > + public =3D getattr(module, "PUBLIC", False) public will be False > + if only_public and not public: > + continue continue isn't reached if not only_public (default value) > + > + doc =3D module.__doc__ > + if doc is None: > + doc =3D "" > + doc =3D doc.strip().split("\n")[0] > + > + name =3D modname.replace("_", "-") > + res.append((name, doc)) > + return res > + > + > +def exists(name): > + """Return whether the given backend exists.""" > + if len(name) =3D=3D 0: > + return False > + name =3D name.replace("-", "_") > + if name =3D=3D "nop": > + return True > + return tracetool.try_import("tracetool.backend." + name)[1] > + > + > +def compatible(backend, format): > + """Whether a backend is compatible with the given format.""" > + if not exists(backend): > + raise ValueError("unknown backend: %s" % backend) > + > + if backend =3D=3D "nop": > + return True > + else: > + func =3D tracetool.try_import("tracetool.backend." + backend, > + format, None)[1] > + return func is not None > + > + > +def _empty(events): > + pass > + > +def generate(backend, format, events): > + """Generate the per-event output for the given (backend, format) p= air.""" > + if not compatible(backend, format): > + raise ValueError("backend '%s' not compatible with format '%s'= " % > + (backend, format)) > + > + if backend =3D=3D "nop": > + func =3D tracetool.try_import("tracetool.format." + format, > + "nop", _empty)[1] > + else: > + func =3D tracetool.try_import("tracetool.backend." + backend, > + format, None)[1] > + > + func(events) > diff --git a/scripts/tracetool/format/__init__.py b/scripts/tracetool/f= ormat/__init__.py > new file mode 100644 > index 0000000..5b37c00 > --- /dev/null > +++ b/scripts/tracetool/format/__init__.py > @@ -0,0 +1,91 @@ > +#!/usr/bin/env python > +# -*- coding: utf-8 -*- > + > +""" > +Format management. > + > + > +Creating new formats > +-------------------- > + > +A new format named 'foo-bar' corresponds to Python module > +'tracetool/frontend/foo_bar.py'. s/frontend/format/ And in later places. > + > +A frontend module should provide a docstring, whose first non-empty li= ne will be > +considered its short description. > + > +All formats must generate their contents through the 'tracetool.out' r= outine. > + > + > +Format functions > +---------------- > + > +All the following functions are optional, and no output will be genera= ted if > +they do not exist. > + > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > +Function Description > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > +begin Called to generate the format-specific file header. > +end Called to generate the format-specific file footer. > +nop Called to generate the per-event contents when the event is d= isabled or > + the selected backend is 'nop'. > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > +""" > + > +__author__ =3D "Llu=EDs Vilanova " > +__copyright__ =3D "Copyright 2012, Llu=EDs Vilanova " > +__license__ =3D "GPL version 2 or (at your option) any later versio= n" > + > +__maintainer__ =3D "Stefan Hajnoczi" > +__email__ =3D "stefanha@linux.vnet.ibm.com" > + > + > +import pkgutil > + > +import tracetool > + > + > +def get_list(): > + """Get a list of (name, description) pairs.""" > + res =3D [] > + for _, modname, _ in pkgutil.iter_modules(tracetool.format.__path_= _): > + module =3D tracetool.try_import("tracetool.format." + modname)= [1] > + > + doc =3D module.__doc__ > + if doc is None: > + doc =3D "" > + doc =3D doc.strip().split("\n")[0] > + > + name =3D modname.replace("_", "-") > + res.append((name, doc)) > + return res > + > + > +def exists(name): > + """Return whether the given format exists.""" > + if len(name) =3D=3D 0: > + return False > + return tracetool.try_import("tracetool.format." + name)[1] > + > + > +def _empty(events): > + pass > + > +def generate_begin(name, events): > + """Generate the header of the format-specific file.""" > + if not exists(name): > + raise ValueError("unknown format: %s" % name) > + > + func =3D tracetool.try_import("tracetool.format." + name, > + "begin", _empty)[1] > + func(events) > + > +def generate_end(name, events): > + """Generate the footer of the format-specific file.""" > + if not exists(name): > + raise ValueError("unknown format: %s" % name) > + > + func =3D tracetool.try_import("tracetool.format." + name, > + "end", _empty)[1] > + func(events) >=20 >=20