qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [RFC PATCH v2 1/8] tracetool: Rewrite infrastructure as


From: Alon Levy
Subject: Re: [Qemu-devel] [RFC PATCH v2 1/8] tracetool: Rewrite infrastructure as python modules
Date: Tue, 27 Mar 2012 17:17:56 +0200
User-agent: Mutt/1.5.21 (2010-09-15)

On Mon, Mar 26, 2012 at 07:37:50PM +0200, Lluís Vilanova wrote:
> Signed-off-by: Lluís Vilanova <address@hidden>

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 <address@hidden>"
> +__copyright__  = "Copyright 2012, Lluís Vilanova <address@hidden>"
> +__license__    = "GPL version 2 or (at your option) any later version"
> +
> +__maintainer__ = "Stefan Hajnoczi"
> +__email__      = "address@hidden"
> +
> +
> +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 <address@hidden>"
> +__copyright__  = "Copyright 2012, Lluís Vilanova <address@hidden>"
> +__license__    = "GPL version 2 or (at your option) any later version"
> +
> +__maintainer__ = "Stefan Hajnoczi"
> +__email__      = "address@hidden"
> +
> +
> +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 <address@hidden>"
> +__copyright__  = "Copyright 2012, Lluís Vilanova <address@hidden>"
> +__license__    = "GPL version 2 or (at your option) any later version"
> +
> +__maintainer__ = "Stefan Hajnoczi"
> +__email__      = "address@hidden"
> +
> +
> +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 <address@hidden>"
> +__copyright__  = "Copyright 2012, Lluís Vilanova <address@hidden>"
> +__license__    = "GPL version 2 or (at your option) any later version"
> +
> +__maintainer__ = "Stefan Hajnoczi"
> +__email__      = "address@hidden"
> +
> +
> +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 via email to

[Prev in Thread] Current Thread [Next in Thread]