[Top][All Lists]
[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)
>
>
- [Qemu-devel] [RFC PATCH v2 0/8] Rewrite tracetool using python modules, Lluís Vilanova, 2012/03/26
- [Qemu-devel] [RFC PATCH v2 1/8] tracetool: Rewrite infrastructure as python modules, Lluís Vilanova, 2012/03/26
- Re: [Qemu-devel] [RFC PATCH v2 1/8] tracetool: Rewrite infrastructure as python modules,
Alon Levy <=
- Re: [Qemu-devel] [RFC PATCH v2 1/8] tracetool: Rewrite infrastructure as python modules, Alon Levy, 2012/03/27
- [Qemu-devel] [PATCH] tracetool.py: always pass --binary, --target-arch, --target-type, Alon Levy, 2012/03/27
- Re: [Qemu-devel] [PATCH] tracetool.py: always pass --binary, --target-arch, --target-type, Lluís Vilanova, 2012/03/27
- Re: [Qemu-devel] [PATCH] tracetool.py: always pass --binary, --target-arch, --target-type, Alon Levy, 2012/03/28
- Re: [Qemu-devel] [PATCH] tracetool.py: always pass --binary, --target-arch, --target-type, Lluís Vilanova, 2012/03/28
[Qemu-devel] [RFC PATCH v2 2/8] tracetool: Add module for the 'c' format, Lluís Vilanova, 2012/03/26
[Qemu-devel] [RFC PATCH v2 3/8] tracetool: Add module for the 'h' format, Lluís Vilanova, 2012/03/26
[Qemu-devel] [RFC PATCH v2 4/8] tracetool: Add support for the 'stderr' backend, Lluís Vilanova, 2012/03/26
[Qemu-devel] [RFC PATCH v2 5/8] tracetool: Add support for the 'simple' backend, Lluís Vilanova, 2012/03/26