qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Harsh Bora <harsh@linux.vnet.ibm.com>
To: "Lluís Vilanova" <vilanova@ac.upc.edu>
Cc: aneesh.kumar@linux.vnet.ibm.com, qemu-devel@nongnu.org,
	stefanha@linux.vnet.ibm.com
Subject: Re: [Qemu-devel] [RFC PATCH v3 1/3] Converting tracetool.sh to tracetool.py
Date: Wed, 11 Jan 2012 12:08:30 +0530	[thread overview]
Message-ID: <4F0D2E66.9010401@linux.vnet.ibm.com> (raw)
In-Reply-To: <87vcojrx20.fsf@ginnungagap.bsc.es>

On 01/11/2012 04:21 AM, Lluís Vilanova wrote:
> Harsh Prateek Bora writes:
>
>> Signed-off-by: Harsh Prateek Bora<harsh@linux.vnet.ibm.com>
>> ---
>>   Makefile.objs        |    6 +-
>>   Makefile.target      |   10 +-
>>   configure            |    7 +-
>>   scripts/tracetool    |  643 --------------------------------------------------
>>   scripts/tracetool.py |  585 +++++++++++++++++++++++++++++++++++++++++++++
>>   5 files changed, 597 insertions(+), 654 deletions(-)
>>   delete mode 100755 scripts/tracetool
>>   create mode 100755 scripts/tracetool.py
>
> [...]
>> diff --git a/scripts/tracetool.py b/scripts/tracetool.py
>> new file mode 100755
>> index 0000000..6874f66
>> --- /dev/null
>> +++ b/scripts/tracetool.py
>> @@ -0,0 +1,585 @@
>> +#!/usr/bin/env python
>> +# Python based tracetool script (Code generator for trace events)
>> +#
>> +# Copyright IBM, Corp. 2011
>> +#
>> +# This work is licensed under the terms of the GNU GPL, version 2.  See
>> +# the COPYING file in the top-level directory.
>> +#
>> +#
>> +
>> +import sys
>> +import getopt
>> +
>> +def usage():
>> +    print "Tracetool: Generate tracing code for trace events file on stdin"
>> +    print "Usage:"
>> +    print sys.argv[0], " --backend=[nop|simple|stderr|dtrace|ust] [-h|-c|-d|--stap]"
>> +    print '''
>> +Backends:
>> +  --nop     Tracing disabled
>> +  --simple  Simple built-in backend
>> +  --stderr  Stderr built-in backend
>> +  --dtrace  DTrace/SystemTAP backend
>> +  --ust     LTTng User Space Tracing 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)
>> +'''
>> +    sys.exit(1)
>> +
>> +def get_name(line, sep='('):
>> +    head, sep, tail = line.partition(sep)
>> +    return head
>> +
>> +def get_args(line, sep1='(', sep2=')'):
>> +    head, sep1, tail = line.partition(sep1)
>> +    args, sep2, fmt_str = tail.partition(sep2)
>> +    return args
>> +
>> +def get_argnames(line, sep=','):
>> +    nfields = 0
>> +    str = []
>> +    args = get_args(line)
>> +    for field in args.split():
>> +      nfields = nfields + 1
>> +      # Drop pointer star
>> +      type, ptr, tail = field.partition('*')
>> +      if type != field:
>> +        field = tail
>> +
>> +      name, sep, tail = field.partition(',')
>> +
>> +      if name == field:
>> +        continue
>> +      str.append(name)
>> +      str.append(", ")
>> +
>> +    if nfields>  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<stdio.h>
>> +#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 ust_h(events):
>> +    print '''#include<ust/tracepoint.h>
>> +#undef mutex_lock
>> +#undef mutex_unlock
>> +#undef inline
>> +#undef wmb'''
>> +
>> +    for event in events:
>> +        if event.argc>  0:
>> +            print '''
>> +DECLARE_TRACE(ust_%(name)s, TP_PROTO(%(args)s), TP_ARGS(%(argnames)s));
>> +#define trace_%(name)s trace_ust_%(name)s''' % {
>> +    'name': event.name,
>> +    'args': event.args,
>> +    'argnames': event.argnames
>> +}
>> +        else:
>> +            print '''
>> +_DECLARE_TRACEPOINT_NOARGS(ust_%(name)s);
>> +#define trace_%(name)s trace_ust_%(name)s''' % {
>> +    'name': event.name,
>> +}
>> +    print
>> +    return
>> +
>> +def ust_c(events):
>> +    print '''#include<ust/marker.h>
>> +#undef mutex_lock
>> +#undef mutex_unlock
>> +#undef inline
>> +#undef wmb
>> +#include "trace.h"'''
>> +    eventlist = list(events)
>> +    for event in eventlist:
>> +        argnames = event.argnames
>> +        if event.argc>  0:
>> +            argnames = ', ' + event.argnames
>> +            print '''
>> +DEFINE_TRACE(ust_%(name)s);
>> +
>> +static void ust_%(name)s_probe(%(args)s)
>> +{
>> +    trace_mark(ust, %(name)s, %(fmt)s%(argnames)s);
>> +}''' % {
>> +    'name': event.name,
>> +    'args': event.args,
>> +    'fmt': event.fmt.rstrip('\n'),
>> +    'argnames': argnames
>> +}
>> +        else:
>> +            print '''
>> +DEFINE_TRACE(ust_%(name)s);
>> +
>> +static void ust_%(name)s_probe(%(args)s)
>> +{
>> +    trace_mark(ust, %(name)s, UST_MARKER_NOARGS);
>> +}''' % {
>> +    'name': event.name,
>> +    'args': event.args,
>> +}
>> +
>> +    # register probes
>> +    print '''
>> +static void __attribute__((constructor)) trace_init(void)
>> +{'''
>> +    for event in eventlist:
>> +        print '    register_trace_ust_%(name)s(ust_%(name)s_probe);' % {
>> +    'name': event.name
>> +}
>> +    print '}'
>> +
>> +    return
>> +
>> +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
>> +    },
>> +
>> +    'ust': {
>> +        'h': ust_h,
>> +        'c': ust_c,
>> +    },
>> +
>> +}
>> +
>> +# 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)
>
> This is not not extracting the event properties (e.g., disable). A set of
> strings should suffice.
>

Ok, I had a misunderstanding about 'disable' being removed completely 
since all events were enabled by default. I will update the patch as 
required. Are there any other properties except 'disable' ?

> Arguments could be converted to an Arguments class (or similar, like
> ArgumentList) and derive the rest from there using methods (e.g., names, types,
> sizestr, arglist, etc.).
>
> If you want, I can send a patch on top of this one with that.

Any improvements are always welcome.

- Harsh

>
>
>> +
>> +# 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", "ust"]
>> +    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)
>
> This should use the "disable" property to establish whether to use output or
> "nop".
>
>> +    trace_gen[output]['end']()
>> +    return
>> +
>> +if __name__ == "__main__":
>> +    main()
>> +
>> --
>> 1.7.1.1
>
> Lluis
>
>

  reply	other threads:[~2012-01-11  6:38 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-01-10 10:59 [Qemu-devel] [RFC PATCH v3 0/3] simpletrace : support var num of args and strings Harsh Prateek Bora
2012-01-10 10:59 ` [Qemu-devel] [RFC PATCH v3 1/3] Converting tracetool.sh to tracetool.py Harsh Prateek Bora
2012-01-10 14:50   ` Stefan Hajnoczi
2012-01-11  6:25     ` Harsh Bora
2012-01-11 10:03       ` Stefan Hajnoczi
2012-01-10 21:45   ` Lluís Vilanova
2012-01-11 17:14     ` Stefan Hajnoczi
2012-01-10 22:51   ` Lluís Vilanova
2012-01-11  6:38     ` Harsh Bora [this message]
2012-01-11  8:46       ` Harsh Bora
2012-01-11 10:50         ` Stefan Hajnoczi
2012-01-12  9:33     ` Stefan Hajnoczi
2012-01-11 10:07   ` Stefan Hajnoczi
2012-01-10 10:59 ` [Qemu-devel] [RFC PATCH v3 2/3] simpletrace-v2: Handle variable number/size of elements per trace record Harsh Prateek Bora
2012-01-10 16:41   ` Stefan Hajnoczi
2012-01-18  9:14     ` Harsh Bora
2012-01-18 10:31       ` Stefan Hajnoczi
2012-01-18 10:41         ` Harsh Bora
2012-01-18 10:52           ` Harsh Bora
2012-01-18 10:59             ` Stefan Hajnoczi
2012-01-18 11:09               ` Harsh Bora
2012-01-10 10:59 ` [Qemu-devel] [RFC PATCH v3 3/3] simpletrace.py: updated log reader script to handle new log format Harsh Prateek Bora
2012-01-11 12:30   ` Stefan Hajnoczi

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=4F0D2E66.9010401@linux.vnet.ibm.com \
    --to=harsh@linux.vnet.ibm.com \
    --cc=aneesh.kumar@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@linux.vnet.ibm.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).