All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alon Levy <alevy@redhat.com>
To: "Lluís Vilanova" <vilanova@ac.upc.edu>
Cc: stefanha@gmail.com, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [RFC PATCH v2 1/8] tracetool: Rewrite infrastructure as python modules
Date: Tue, 27 Mar 2012 17:17:56 +0200	[thread overview]
Message-ID: <20120327151756.GK32389@garlic> (raw)
In-Reply-To: <20120326173750.20814.75373.stgit@ginnungagap.bsc.es>

On Mon, Mar 26, 2012 at 07:37:50PM +0200, Lluís Vilanova wrote:
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>

Hi,

 Some comments inline.

Alon

> ---
>  Makefile.objs                         |    6 
>  Makefile.target                       |   13 -
>  configure                             |    4 
>  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
> 
> 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.mak
> -	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(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,sh $(SRC_PATH)/scripts/tracetool --$(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)
> @@ -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)/config-host.mak
> -	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(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 63cf769..fe28e8b 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -59,12 +59,13 @@ TARGET_TYPE=system
>  endif
>  
>  $(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=stap \
> +		--backend=$(TRACE_BACKEND) \
> +		--binary=$(bindir)/$(QEMU_PROG) \
> +		--target-arch=$(TARGET_ARCH) \
> +		--target-type=$(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 documentation build"
>  echo "  --disable-vhost-net      disable vhost-net acceleration support"
>  echo "  --enable-vhost-net       enable vhost-net acceleration support"
>  echo "  --enable-trace-backend=B Set trace backend"
> -echo "                           Available backends:" $("$source_path"/scripts/tracetool --list-backends)
> +echo "                           Available backends:" $($python "$source_path"/scripts/tracetool.py --list-backends)
>  echo "  --with-trace-file=NAME   Full PATH,NAME of file to store traces"
>  echo "                           Default:trace-<pid>"
>  echo "  --disable-spice          disable spice"
> @@ -2654,7 +2654,7 @@ fi
>  ##########################################
>  # check if trace backend exists
>  
> -sh "$source_path/scripts/tracetool" "--$trace_backend" --check-backend > /dev/null 2> /dev/null
> +$python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --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.  See
> -# the COPYING file in the top-level directory.
> -
> -# Disable pathname expansion, makes processing text with '*' characters simpler
> -set -f
> -
> -usage()
> -{
> -    cat >&2 <<EOF
> -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 'user')
> -  --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=${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=${1%%\(*}
> -    props=${props% *}
> -    for prop in $props; do
> -        if [ "$prop" = "$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=${1#*\(}
> -    args=${args%%\)*}
> -    echo "$args"
> -}
> -
> -# Get the argument name list of a trace event
> -get_argnames()
> -{
> -    local nfields field name sep
> -    nfields=0
> -    sep="$2"
> -    for field in $(get_args "$1"); do
> -        nfields=$((nfields + 1))
> -
> -        # Drop pointer star
> -        field=${field#\*}
> -
> -        # Only argument names have commas at the end
> -        name=${field%,}
> -        test "$field" = "$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=0
> -    for name in $(get_argnames "$1", ","); do
> -        argc=$((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=$(get_name "$1")
> -    args=$(get_args "$1")
> -
> -    # Define an empty function for the trace event
> -    cat <<EOF
> -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 <<EOF
> -#include "trace/simple.h"
> -EOF
> -
> -    simple_event_num=0
> -}
> -
> -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=$(get_name "$1")
> -    args=$(get_args "$1")
> -    argc=$(get_argc "$1")
> -
> -    trace_args="$simple_event_num"
> -    if [ "$argc" -gt 0 ]
> -    then
> -        trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
> -    fi
> -
> -    cat <<EOF
> -static inline void trace_$name($args)
> -{
> -    trace$argc($trace_args);
> -}
> -EOF
> -
> -    simple_event_num=$((simple_event_num + 1))
> -}
> -
> -linetoh_end_simple()
> -{
> -    cat <<EOF
> -#define NR_TRACE_EVENTS $simple_event_num
> -extern TraceEvent trace_list[NR_TRACE_EVENTS];
> -EOF
> -}
> -
> -linetoc_begin_simple()
> -{
> -    cat <<EOF
> -#include "trace.h"
> -
> -TraceEvent trace_list[] = {
> -EOF
> -    simple_event_num=0
> -
> -}
> -
> -linetoc_simple()
> -{
> -    local name
> -    name=$(get_name "$1")
> -    cat <<EOF
> -{.tp_name = "$name", .state=0},
> -EOF
> -    simple_event_num=$((simple_event_num + 1))
> -}
> -
> -linetoc_end_simple()
> -{
> -    cat <<EOF
> -};
> -EOF
> -}
> -
> -#STDERR
> -linetoh_begin_stderr()
> -{
> -    cat <<EOF
> -#include <stdio.h>
> -#include "trace/stderr.h"
> -
> -extern TraceEvent trace_list[];
> -EOF
> -
> -    stderr_event_num=0
> -}
> -
> -linetoh_stderr()
> -{
> -    local name args argnames argc fmt
> -    name=$(get_name "$1")
> -    args=$(get_args "$1")
> -    argnames=$(get_argnames "$1" ",")
> -    argc=$(get_argc "$1")
> -    fmt=$(get_fmt "$1")
> -
> -    if [ "$argc" -gt 0 ]; then
> -        argnames=", $argnames"
> -    fi
> -
> -    cat <<EOF
> -static inline void trace_$name($args)
> -{
> -    if (trace_list[$stderr_event_num].state != 0) {
> -        fprintf(stderr, "$name " $fmt "\n" $argnames);
> -    }
> -}
> -EOF
> -    stderr_event_num=$((stderr_event_num + 1))
> -
> -}
> -
> -linetoh_end_stderr()
> -{
> -    cat <<EOF
> -#define NR_TRACE_EVENTS $stderr_event_num
> -EOF
> -}
> -
> -linetoc_begin_stderr()
> -{
> -    cat <<EOF
> -#include "trace.h"
> -
> -TraceEvent trace_list[] = {
> -EOF
> -    stderr_event_num=0
> -}
> -
> -linetoc_stderr()
> -{
> -    local name
> -    name=$(get_name "$1")
> -    cat <<EOF
> -{.tp_name = "$name", .state=0},
> -EOF
> -    stderr_event_num=$(($stderr_event_num + 1))
> -}
> -
> -linetoc_end_stderr()
> -{
> -    cat <<EOF
> -};
> -EOF
> -}
> -#END OF STDERR
> -
> -# Clean up after UST headers which pollute the namespace
> -ust_clean_namespace() {
> -    cat <<EOF
> -#undef mutex_lock
> -#undef mutex_unlock
> -#undef inline
> -#undef wmb
> -EOF
> -}
> -
> -linetoh_begin_ust()
> -{
> -    echo "#include <ust/tracepoint.h>"
> -    ust_clean_namespace
> -}
> -
> -linetoh_ust()
> -{
> -    local name args argnames
> -    name=$(get_name "$1")
> -    args=$(get_args "$1")
> -    argnames=$(get_argnames "$1", ",")
> -
> -    cat <<EOF
> -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 <<EOF
> -#include <ust/marker.h>
> -$(ust_clean_namespace)
> -#include "trace.h"
> -EOF
> -}
> -
> -linetoc_ust()
> -{
> -    local name args argnames fmt
> -    name=$(get_name "$1")
> -    args=$(get_args "$1")
> -    argnames=$(get_argnames "$1", ",")
> -    [ -z "$argnames" ] || argnames=", $argnames"
> -    fmt=$(get_fmt "$1")
> -
> -    cat <<EOF
> -DEFINE_TRACE(ust_$name);
> -
> -static void ust_${name}_probe($args)
> -{
> -    trace_mark(ust, $name, $fmt$argnames);
> -}
> -EOF
> -
> -    # Collect names for later
> -    names="$names $name"
> -}
> -
> -linetoc_end_ust()
> -{
> -    cat <<EOF
> -static void __attribute__((constructor)) trace_init(void)
> -{
> -EOF
> -
> -    for name in $names; do
> -        cat <<EOF
> -    register_trace_ust_$name(ust_${name}_probe);
> -EOF
> -    done
> -
> -    echo "}"
> -}
> -
> -linetoh_begin_dtrace()
> -{
> -    cat <<EOF
> -#include "trace-dtrace.h"
> -EOF
> -}
> -
> -linetoh_dtrace()
> -{
> -    local name args argnames nameupper
> -    name=$(get_name "$1")
> -    args=$(get_args "$1")
> -    argnames=$(get_argnames "$1", ",")
> -
> -    nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
> -
> -    # Define an empty function for the trace event
> -    cat <<EOF
> -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 <<EOF
> -provider qemu {
> -EOF
> -}
> -
> -linetod_dtrace()
> -{
> -    local name args
> -    name=$(get_name "$1")
> -    args=$(get_args "$1")
> -
> -    # DTrace provider syntax expects foo() for empty
> -    # params, not foo(void)
> -    if [ "$args" = "void" ]; then
> -       args=""
> -    fi
> -
> -    # Define prototype for probe arguments
> -    cat <<EOF
> -        probe $name($args);
> -EOF
> -}
> -
> -linetod_end_dtrace()
> -{
> -    cat <<EOF
> -};
> -EOF
> -}
> -
> -linetostap_begin_dtrace()
> -{
> -    return
> -}
> -
> -linetostap_dtrace()
> -{
> -    local i arg name args arglist
> -    name=$(get_name "$1")
> -    args=$(get_args "$1")
> -    arglist=$(get_argnames "$1", "")
> -
> -    # Define prototype for probe arguments
> -    cat <<EOF
> -probe $probeprefix.$name = process("$binary").mark("$name")
> -{
> -EOF
> -
> -    i=1
> -    for arg in $arglist
> -    do
> -        # 'limit' is a reserved keyword
> -        if [ "$arg" = "limit" ]; then
> -          arg="_limit"
> -        fi
> -        cat <<EOF
> -  $arg = \$arg$i;
> -EOF
> -        i="$((i+1))"
> -    done
> -
> -    cat <<EOF
> -}
> -EOF
> -}
> -
> -linetostap_end_dtrace()
> -{
> -    return
> -}
> -
> -# Process stdin by calling begin, line, and end functions for the backend
> -convert()
> -{
> -    local begin process_line end str name NAME enabled
> -    begin="lineto$1_begin_$backend"
> -    process_line="lineto$1_$backend"
> -    end="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=0
> -        else
> -            "$process_line" "$str"
> -            enabled=1
> -        fi
> -        if [ "$1" = "h" ]; then
> -            name=$(get_name "$str")
> -            NAME=$(echo $name | tr '[:lower:]' '[:upper:]')
> -            echo "#define TRACE_${NAME}_ENABLED ${enabled}"
> -        fi
> -    done
> -
> -    echo
> -    "$end"
> -}
> -
> -tracetoh()
> -{
> -    cat <<EOF
> -#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 != "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 != "dtrace" ]; then
> -       echo "SystemTAP tapset generator not applicable to $backend backend"
> -       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="qemu.$targettype.$targetarch";
> -    fi
> -    echo "/* This file is autogenerated by tracetool, do not edit. */"
> -    convert stap
> -}
> -
> -
> -backend=
> -output=
> -binary=
> -targettype=
> -targetarch=
> -probeprefix=
> -
> -
> -until [ -z "$1" ]
> -do
> -  case "$1" in
> -    "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
> -
> -    "--binary") shift ; binary="$1" ;;
> -    "--target-arch") shift ; targetarch="$1" ;;
> -    "--target-type") shift ; targettype="$1" ;;
> -    "--probe-prefix") shift ; probeprefix="$1" ;;
> -
> -    "-h" | "-c" | "-d") output="${1#-}" ;;
> -    "--stap") output="${1#--}" ;;
> -
> -    "--check-backend") exit 0 ;; # used by ./configure to test for backend
> -
> -    "--list-backends") # used by ./configure to list available backends
> -          echo "nop simple stderr ust dtrace"
> -          exit 0
> -          ;;
> -
> -    *)
> -      usage;;
> -  esac
> -  shift
> -done
> -
> -if [ "$backend" = "" -o "$output" = "" ]; then
> -  usage
> -fi
> -
> -gen="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__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
> +__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
> +__license__    = "GPL version 2 or (at your option) any later version"
> +
> +__maintainer__ = "Stefan Hajnoczi"
> +__email__      = "stefanha@linux.vnet.ibm.com"
> +
> +
> +import sys
> +import getopt
> +
> +from tracetool import error_write, out
> +import tracetool.backend
> +import tracetool.format
> +
> +
> +_SCRIPT = ""

I don't understand the point of this, why not use sys.argv[0] directly?

> +
> +def error_opt(msg = None):
> +    if msg is not None:
> +        error_write("Error: " + msg + "\n")
> +
> +    backend_descr = "\n".join([ "    %-15s %s" % (n, d)
> +                                for n,d in tracetool.backend.get_list() ])
> +    format_descr = "\n".join([ "    %-15s %s" % (n, d)
> +                               for n,d in tracetool.format.get_list() ])
> +    error_write("""\
> +Usage: %(script)s --format=<format> --backend=<backend> [<options>]
> +
> +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 = sys.argv[0]
> +
> +    long_opts  = [ "backend=", "format=", "help", "list-backends", "check-backend" ]
> +    long_opts += [ "binary=", "target-type=", "target-arch=", "probe-prefix=" ]
> +
> +    try:
> +        opts, args = getopt.getopt(args[1:], "", long_opts)
> +    except getopt.GetoptError as err:
> +        error_opt(str(err))
> +
> +    check_backend = False
> +    arg_backend = ""
> +    arg_format = ""
> +    for opt, arg in opts:
> +        if opt == "--help":
> +            error_opt()
> +
> +        elif opt == "--backend":
> +            arg_backend = arg
> +        elif opt == "--format":
> +            arg_format = arg
> +
> +        elif opt == "--list-backends":
> +            public_backends = tracetool.backend.get_list(only_public = True)
> +            out(", ".join([ b for b,_ in public_backends ]))
> +            sys.exit(0)
> +        elif opt == "--check-backend":
> +            check_backend = 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 = {}
> +
> +    try:
> +        tracetool.generate(sys.stdin, arg_format, arg_backend, **kwargs)
> +    except tracetool.TracetoolError as e:
> +        error_opt(str(e))
> +
> +if __name__ == "__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__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
> +__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
> +__license__    = "GPL version 2 or (at your option) any later version"
> +
> +__maintainer__ = "Stefan Hajnoczi"
> +__email__      = "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 = []
> +        for arg in arg_str.split(","):
> +            arg = arg.strip()
> +            parts = arg.split()
> +            head, sep, tail = parts[-1].rpartition("*")
> +            parts = parts[:-1]
> +            if tail == "void":
> +                assert len(parts) == 0 and sep == ""
> +                continue
> +            arg_type = " ".join(parts + [ " ".join([head, sep]).strip() ]).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) == 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 = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?")
> +
> +    _VALID_PROPS = set(["disable"])
> +
> +    def __init__(self, line):
> +        m = self._CRE.match(line)
> +        assert m is not None
> +        groups = m.groupdict('')
> +        self.name = groups["name"]
> +        self.fmt = groups["fmt"]
> +        self.properties = groups["props"].split()
> +        self.args = Arguments(groups["args"])
> +
> +        unknown_props = set(self.properties) - self._VALID_PROPS
> +        if len(unknown_props) > 0:
> +            raise ValueError("Unknown properties: %s" % ", ".join(unknown_props))
> +
> +
> +def _read_events(fobj):
> +    res = []
> +    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 = None, attr_default = 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 module or
> +    object or attribute value.
> +    """
> +    mod_name = mod_name.replace("-", "_")
> +    try:
> +        module = __import__(mod_name, fromlist=["__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 = str(format)
> +    if len(format) is 0:
> +        raise TracetoolError("format not set")
> +    mformat = format.replace("-", "_")
> +    if not tracetool.format.exists(mformat):
> +        raise TracetoolError("unknown format: %s" % format)
> +
> +    backend = str(backend)
> +    if len(backend) is 0:
> +        raise TracetoolError("backend not set")
> +    mbackend = 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 = _read_events(fevents)
> +
> +    if backend == "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 line will be
> +considered its short description.
> +
> +All backends must generate their contents through the 'tracetool.out' routine.
> +
> +
> +Backend attributes
> +------------------
> +
> +========= ====================================================================
> +Attribute Description
> +========= ====================================================================
> +PUBLIC    If exists and is set to 'True', the backend is considered "public".
> +========= ====================================================================
> +
> +
> +Backend functions
> +-----------------
> +
> +======== =======================================================================
> +Function Description
> +======== =======================================================================
> +<format> Called to generate the format- and backend-specific code for each of
> +         the specified events. If the function does not exist, the backend is
> +         considered not compatible with the given format.
> +======== =======================================================================
> +"""
> +
> +__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
> +__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
> +__license__    = "GPL version 2 or (at your option) any later version"
> +
> +__maintainer__ = "Stefan Hajnoczi"
> +__email__      = "stefanha@linux.vnet.ibm.com"
> +
> +
> +import pkgutil
> +
> +import tracetool
> +
> +
> +def get_list(only_public = False):
> +    """Get a list of (name, description) pairs."""
> +    res = [("nop", "Tracing disabled.")]
> +    for _, modname, _ in pkgutil.iter_modules(tracetool.backend.__path__):
> +        module = tracetool.try_import("tracetool.backend." + modname)[1]
> +

Here module can be None if ImportError was raised in try_import.

> +        public = 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 = module.__doc__
> +        if doc is None:
> +            doc = ""
> +        doc = doc.strip().split("\n")[0]
> +
> +        name = modname.replace("_", "-")
> +        res.append((name, doc))
> +    return res
> +
> +
> +def exists(name):
> +    """Return whether the given backend exists."""
> +    if len(name) == 0:
> +        return False
> +    name = name.replace("-", "_")
> +    if name == "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 == "nop":
> +        return True
> +    else:
> +        func = 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) pair."""
> +    if not compatible(backend, format):
> +        raise ValueError("backend '%s' not compatible with format '%s'" %
> +                         (backend, format))
> +
> +    if backend == "nop":
> +        func = tracetool.try_import("tracetool.format." + format,
> +                                    "nop", _empty)[1]
> +    else:
> +        func = tracetool.try_import("tracetool.backend." + backend,
> +                                    format, None)[1]
> +
> +    func(events)
> diff --git a/scripts/tracetool/format/__init__.py b/scripts/tracetool/format/__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 line will be
> +considered its short description.
> +
> +All formats must generate their contents through the 'tracetool.out' routine.
> +
> +
> +Format functions
> +----------------
> +
> +All the following functions are optional, and no output will be generated if
> +they do not exist.
> +
> +======== =======================================================================
> +Function Description
> +======== =======================================================================
> +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 disabled or
> +         the selected backend is 'nop'.
> +======== =======================================================================
> +"""
> +
> +__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
> +__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
> +__license__    = "GPL version 2 or (at your option) any later version"
> +
> +__maintainer__ = "Stefan Hajnoczi"
> +__email__      = "stefanha@linux.vnet.ibm.com"
> +
> +
> +import pkgutil
> +
> +import tracetool
> +
> +
> +def get_list():
> +    """Get a list of (name, description) pairs."""
> +    res = []
> +    for _, modname, _ in pkgutil.iter_modules(tracetool.format.__path__):
> +        module = tracetool.try_import("tracetool.format." + modname)[1]
> +
> +        doc = module.__doc__
> +        if doc is None:
> +            doc = ""
> +        doc = doc.strip().split("\n")[0]
> +
> +        name = modname.replace("_", "-")
> +        res.append((name, doc))
> +    return res
> +
> +
> +def exists(name):
> +    """Return whether the given format exists."""
> +    if len(name) == 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 = 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 = tracetool.try_import("tracetool.format." + name,
> +                                "end", _empty)[1]
> +    func(events)
> 
> 

  reply	other threads:[~2012-03-27 15:18 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-26 17:37 [Qemu-devel] [RFC PATCH v2 0/8] Rewrite tracetool using python modules Lluís Vilanova
2012-03-26 17:37 ` [Qemu-devel] [RFC PATCH v2 1/8] tracetool: Rewrite infrastructure as " Lluís Vilanova
2012-03-27 15:17   ` Alon Levy [this message]
2012-03-27 17:47     ` Lluís Vilanova
2012-03-27 15:21   ` Alon Levy
2012-03-27 16:37   ` [Qemu-devel] [PATCH] tracetool.py: always pass --binary, --target-arch, --target-type Alon Levy
2012-03-27 18:01     ` Lluís Vilanova
2012-03-28  9:35       ` Alon Levy
2012-03-28 10:29         ` Lluís Vilanova
2012-03-26 17:37 ` [Qemu-devel] [RFC PATCH v2 2/8] tracetool: Add module for the 'c' format Lluís Vilanova
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 3/8] tracetool: Add module for the 'h' format Lluís Vilanova
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 4/8] tracetool: Add support for the 'stderr' backend Lluís Vilanova
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 5/8] tracetool: Add support for the 'simple' backend Lluís Vilanova
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 6/8] tracetool: Add support for the 'ust' backend Lluís Vilanova
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 7/8] tracetool: Add support for the 'dtrace' backend Lluís Vilanova
2012-03-27 15:19   ` Alon Levy
2012-03-27 16:20   ` Alon Levy
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 8/8] tracetool: Add MAINTAINERS info Lluís Vilanova

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120327151756.GK32389@garlic \
    --to=alevy@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@gmail.com \
    --cc=vilanova@ac.upc.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.