From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:57994) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RkHR4-0008JT-Md for qemu-devel@nongnu.org; Mon, 09 Jan 2012 10:47:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RkHQt-0007IA-I6 for qemu-devel@nongnu.org; Mon, 09 Jan 2012 10:46:58 -0500 Received: from e28smtp04.in.ibm.com ([122.248.162.4]:32793) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RkHQs-0007Hr-3H for qemu-devel@nongnu.org; Mon, 09 Jan 2012 10:46:47 -0500 Received: from /spool/local by e28smtp04.in.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 9 Jan 2012 21:16:40 +0530 Received: from d28av03.in.ibm.com (d28av03.in.ibm.com [9.184.220.65]) by d28relay05.in.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q09FkMjk3461136 for ; Mon, 9 Jan 2012 21:16:23 +0530 Received: from d28av03.in.ibm.com (loopback [127.0.0.1]) by d28av03.in.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q09FkLn8028298 for ; Tue, 10 Jan 2012 02:46:22 +1100 From: Harsh Prateek Bora Date: Mon, 9 Jan 2012 21:16:17 +0530 Message-Id: <1326123980-6038-2-git-send-email-harsh@linux.vnet.ibm.com> In-Reply-To: <1326123980-6038-1-git-send-email-harsh@linux.vnet.ibm.com> References: <1326123980-6038-1-git-send-email-harsh@linux.vnet.ibm.com> Subject: [Qemu-devel] [RFC PATCH v2 1/4] Converting tracetool.sh to tracetool.py List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: aneesh.kumar@linux.vnet.ibm.com, mathieu.desnoyers@efficios.com, vilanova@ac.upc.edu, stefanha@linux.vnet.ibm.com Note: Upstream Qemu have build issues with LTTng ust backend, as the trace event APIs are not yet stable in ust and therefore ust backend is not supported in this script as of now. Once the ust API stablises, this script can be updated for ust backend also. Signed-off-by: Harsh Prateek Bora --- scripts/tracetool | 643 -------------------------------------------------- scripts/tracetool.py | 505 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 505 insertions(+), 643 deletions(-) delete mode 100755 scripts/tracetool create mode 100755 scripts/tracetool.py diff --git a/scripts/tracetool b/scripts/tracetool deleted file mode 100755 index 4c9951d..0000000 --- a/scripts/tracetool +++ /dev/null @@ -1,643 +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 < 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 < -#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 <" - ust_clean_namespace -} - -linetoh_ust() -{ - local name args argnames - name=$(get_name "$1") - args=$(get_args "$1") - argnames=$(get_argnames "$1", ",") - - cat < -$(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 < 1: + str.append(name) + return ''.join(str) + else: + return '' + +def get_argc(line): + argc = 0 + argnames = get_argnames(line) + if argnames: + for name in argnames.split(','): + argc = argc + 1 + return argc + +def get_fmt(line, sep=')'): + event, sep, fmt = line.partition(sep) + return fmt + +def calc_sizeofargs(line): + args = get_args(line) + argc = get_argc(line) + strtype = ('const char*', 'char*', 'const char *', 'char *') + str = [] + newstr = "" + if argc > 0: + str = args.split(',') + for elem in str: + if elem.lstrip().startswith(strtype): #strings + type, sep, var = elem.rpartition('*') + newstr = newstr+"4 + strlen("+var.lstrip()+") + " + #elif '*' in elem: + # newstr = newstr + "4 + " # pointer vars + else: + #type, sep, var = elem.rpartition(' ') + #newstr = newstr+"sizeof("+type.lstrip()+") + " + newstr = newstr + '8 + ' + newstr = newstr + '0' # for last + + return newstr + + +def trace_h_begin(): + print '''#ifndef TRACE_H +#define TRACE_H + +/* This file is autogenerated by tracetool, do not edit. */ + +#include "qemu-common.h"''' + return + +def trace_h_end(): + print '#endif /* TRACE_H */' + return + +def trace_c_begin(): + print '/* This file is autogenerated by tracetool, do not edit. */' + return + +def trace_c_end(): + # nop, required for trace_gen + return + +def nop_h(events): + print + for event in events: + print '''static inline void trace_%(name)s(%(args)s) +{ +} +''' % { + 'name': event.name, + 'args': event.args +} + return + +def nop_c(events): + # nop, reqd for converters + return + + +def simple_h(events): + print '#include "trace/simple.h"' + print + for event in events: + print 'void trace_%(name)s(%(args)s);' % { + 'name': event.name, + 'args': event.args +} + print + print '#define NR_TRACE_EVENTS %d' % (event.num + 1) + print 'extern TraceEvent trace_list[NR_TRACE_EVENTS];' + + return + +def is_string(arg): + strtype = ('const char*', 'char*', 'const char *', 'char *') + if arg.lstrip().startswith(strtype): + return True + else: + return False + +def simple_c(events): + rec_off = 0 + print '#include "trace.h"' + print '#include "trace/simple.h"' + print + print 'TraceEvent trace_list[] = {' + print + eventlist = list(events) + for event in eventlist: + print '{.tp_name = "%(name)s", .state=0},' % { + 'name': event.name +} + print + print '};' + print + for event in eventlist: + argc = event.argc + print '''void trace_%(name)s(%(args)s) +{ + unsigned int tbuf_idx, rec_off; + uint64_t var64 __attribute__ ((unused)); + uint64_t pvar64 __attribute__ ((unused)); + uint32_t slen __attribute__ ((unused)); + + if (!trace_list[%(event_id)s].state) { + return; + } +''' % { + 'name': event.name, + 'args': event.args, + 'event_id': event.num, +} + print ''' + tbuf_idx = trace_alloc_record(%(event_id)s, %(sizestr)s); + rec_off = (tbuf_idx + ST_V2_REC_HDR_LEN) %% TRACE_BUF_LEN; /* seek record header */ +''' % {'event_id': event.num, 'sizestr': event.sizestr,} + + if argc > 0: + str = event.arglist + for elem in str: + if is_string(elem): # if string + type, sep, var = elem.rpartition('*') + print ''' + slen = strlen(%(var)s); + write_to_buffer(rec_off, (uint8_t*)&slen, sizeof(slen)); + rec_off += sizeof(slen);''' % { + 'var': var.lstrip() +} + print ''' + write_to_buffer(rec_off, (uint8_t*)%(var)s, slen); + rec_off += slen;''' % { + 'var': var.lstrip() +} + elif '*' in elem: # pointer var (not string) + type, sep, var = elem.rpartition('*') + print ''' + pvar64 = (uint64_t)(uint64_t*)%(var)s; + write_to_buffer(rec_off, (uint8_t*)&pvar64, sizeof(uint64_t)); + rec_off += sizeof(uint64_t);''' % { + 'var': var.lstrip() +} + else: # primitive data type + type, sep, var = elem.rpartition(' ') + print ''' + var64 = (uint64_t)%(var)s; + write_to_buffer(rec_off, (uint8_t*)&var64, sizeof(uint64_t)); + rec_off += sizeof(uint64_t);''' % { + 'var': var.lstrip() +} + print ''' + trace_mark_record_complete(tbuf_idx);''' + print '}' + print + + return + +def stderr_h(events): + print '''#include +#include "trace/stderr.h" + +extern TraceEvent trace_list[];''' + for event in events: + argnames = event.argnames + if event.argc > 0: + argnames = ', ' + event.argnames + else: + argnames = '' + print ''' +static inline void trace_%(name)s(%(args)s) +{ + if (trace_list[%(event_num)s].state != 0) { + fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s); + } +}''' % { + 'name': event.name, + 'args': event.args, + 'event_num': event.num, + 'fmt': event.fmt.rstrip('\n'), + 'argnames': argnames +} + print + print '#define NR_TRACE_EVENTS %d' % (event.num + 1) + +def stderr_c(events): + print '''#include "trace.h" + +TraceEvent trace_list[] = { +''' + for event in events: + print '{.tp_name = "%(name)s", .state=0},' % { + 'name': event.name +} + print + print '};' + +def dtrace_h(events): + print '#include "trace-dtrace.h"' + print + for event in events: + print '''static inline void trace_%(name)s(%(args)s) { + if (QEMU_%(uppername)s_ENABLED()) { + QEMU_%(uppername)s(%(argnames)s); + } +} +''' % { + 'name': event.name, + 'args': event.args, + 'uppername': event.name.upper(), + 'argnames': event.argnames, +} + +def dtrace_c(events): + return # No need for function definitions in dtrace backend + +def dtrace_d(events): + print 'provider qemu {' + for event in events: + args = event.args + + # DTrace provider syntax expects foo() for empty + # params, not foo(void) + if args == 'void': + args = '' + + # Define prototype for probe arguments + print ''' + probe %(name)s(%(args)s);''' % { + 'name': event.name, + 'args': args +} + print + print '};' + return + +def dtrace_stp(events): + for event in events: + # Define prototype for probe arguments + print ''' +probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s") +{''' % { + 'probeprefix': probeprefix, + 'name': event.name, + 'binary': binary +} + i = 1 + if event.argc > 0: + for arg in event.argnames.split(','): + # 'limit' is a reserved keyword + if arg == 'limit': + arg = '_limit' + print ' %s = $arg%d;' % (arg.lstrip(), i) + i += 1 + print '}' + print + return + +def trace_stap_begin(): + global probeprefix + if backend != "dtrace": + print 'SystemTAP tapset generator not applicable to %s backend' % backend + sys.exit(1) + if binary == "": + print '--binary is required for SystemTAP tapset generator' + sys.exit(1) + if ((probeprefix == "") and (targettype == "")): + print '--target-type is required for SystemTAP tapset generator' + sys.exit(1) + if ((probeprefix == "") and (targetarch == "")): + print '--target-arch is required for SystemTAP tapset generator' + sys.exit(1) + if probeprefix == "": + probeprefix = 'qemu.' + targettype + '.' + targetarch + print '/* This file is autogenerated by tracetool, do not edit. */' + return + +def trace_stap_end(): + return #nop, reqd for trace_gen + +def trace_d_begin(): + if backend != 'dtrace': + print 'DTrace probe generator not applicable to %s backend' % backend + sys.exit(1) + print '/* This file is autogenerated by tracetool, do not edit. */' + +def trace_d_end(): + return #nop, reqd for trace_gen + + +# Registry of backends and their converter functions +converters = { + 'simple': { + 'h': simple_h, + 'c': simple_c, + }, + + 'nop': { + 'h': nop_h, + 'c': nop_c, + }, + + 'stderr': { + 'h': stderr_h, + 'c': stderr_c, + }, + + 'dtrace': { + 'h': dtrace_h, + 'c': dtrace_c, + 'd': dtrace_d, + 'stap': dtrace_stp + }, +} + +# Trace file header and footer code generators +trace_gen = { + 'h': { + 'begin': trace_h_begin, + 'end': trace_h_end, + }, + 'c': { + 'begin': trace_c_begin, + 'end': trace_c_end, + }, + 'd': { + 'begin': trace_d_begin, + 'end': trace_d_end, + }, + 'stap': { + 'begin': trace_stap_begin, + 'end': trace_stap_end, + }, +} + +# A trace event +class Event(object): + def __init__(self, num, line): + self.num = num + self.args = get_args(line) + self.arglist = self.args.split(',') + self.name = get_name(line) + self.argc = get_argc(line) + self.argnames = get_argnames(line) + self.sizestr = calc_sizeofargs(line) + self.fmt = get_fmt(line) + +# Generator that yields Event objects given a trace-events file object +def read_events(fobj): + event_num = 0 + for line in fobj: + if not line.strip(): + continue + if line.lstrip().startswith('#'): + continue + yield Event(event_num, line) + event_num += 1 + +backend = "" +output = "" +binary = "" +targettype = "" +targetarch = "" +probeprefix = "" + +def main(): + global backend, output, binary, targettype, targetarch, probeprefix + supported_backends = ["simple", "nop", "stderr", "dtrace"] + short_options = "hcd" + long_options = ["stap", "backend=", "binary=", "target-arch=", "target-type=", "probe-prefix=", "list-backends", "check-backend"] + try: + opts, args = getopt.getopt(sys.argv[1:], short_options, long_options) + except getopt.GetoptError, err: + # print help information and exit: + print str(err) # will print something like "option -a not recognized" + usage() + sys.exit(2) + for opt, arg in opts: + if opt == '-h': + output = 'h' + elif opt == '-c': + output = 'c' + elif opt == '-d': + output = 'd' + elif opt == '--stap': + output = 'stap' + elif opt == '--backend': + backend = arg + elif opt == '--binary': + binary = arg + elif opt == '--target-arch': + targetarch = arg + elif opt == '--target-type': + targettype = arg + elif opt == '--probe-prefix': + probeprefix = arg + elif opt == '--list-backends': + print 'simple, nop, stderr, dtrace' + sys.exit(0) + elif opt == "--check-backend": + if any(backend in s for s in supported_backends): + sys.exit(0) + else: + sys.exit(1) + else: + #assert False, "unhandled option" + print "unhandled option: ", opt + usage() + + if backend == "" or output == "": + usage() + sys.exit(0) + + events = read_events(sys.stdin) + trace_gen[output]['begin']() + converters[backend][output](events) + trace_gen[output]['end']() + return + +if __name__ == "__main__": + main() + -- 1.7.1.1