Patchwork [RFC,1/4] Converting tracetool.sh to tracetool.py

login
register
mail settings
Submitter Harsh Prateek Bora
Date Jan. 2, 2012, 6:50 a.m.
Message ID <1325487023-10613-2-git-send-email-harsh@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/133800/
State New
Headers show

Comments

Harsh Prateek Bora - Jan. 2, 2012, 6:50 a.m.
Note: As of now, tracetool.py only supports simpletrace backend.
TODO: Add support for other tracing backends.

Signed-off-by: Harsh Prateek Bora <harsh@linux.vnet.ibm.com>
---
 scripts/tracetool.py |  299 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 299 insertions(+), 0 deletions(-)
 create mode 100755 scripts/tracetool.py

Patch

diff --git a/scripts/tracetool.py b/scripts/tracetool.py
new file mode 100755
index 0000000..95c3c2e
--- /dev/null
+++ b/scripts/tracetool.py
@@ -0,0 +1,299 @@ 
+#!/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."
+    print "           Takes input from stdin, output can be redirected from stdout."
+    print "Usage:"
+    print sys.argv[0]+" --backend=simple [-h | -c]"
+    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 cast_args_to_uint64_t(line):
+    str = []
+    argnames = line.argnames
+    if argnames:
+      for name in argnames.split():
+        str.append("(uint64_t)(uintptr_t)")
+        str.append(name)
+    return ''.join(str)
+
+# trace args to be generated for simpletrace backend
+def trace_args_simple(event):
+    if event.argc:
+        return (str(event.num) + ', ' + cast_args_to_uint64_t(event))
+    else:
+        return str(event.num)
+
+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 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
+
+# Registry of backends and their converter functions
+converters = {
+    'simple': {
+        'h': simple_h,
+	'c': simple_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,
+    },
+}
+
+# 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)
+
+
+# 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
+
+def main():
+    supported_backends = ["simple", "todo"]
+    try:
+      opts, args = getopt.getopt(sys.argv[1:], "hc", ["backend=", "list-backends", "check-backend"])
+    except getopt.GetoptError, err:
+      # print help information and exit:
+      print str(err) # will print something like "option -a not recognized"
+      usage()
+      sys.exit(2)
+    output = ""
+    backend = ""
+    for opt, arg in opts:
+      if opt == "-h":
+        output = 'h'
+      elif opt == "-c":
+        output = 'c'
+      elif opt == "--backend":
+        backend = arg
+      elif opt == "--list-backends":
+        print "simple (other backends not supported yet)"
+        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()
+