Note: As of now, tracetool.py only supports simpletrace backend. TODO: Add support for other tracing backends.
Signed-off-by: Harsh Prateek Bora <ha...@linux.vnet.ibm.com> --- scripts/tracetool.py | 299 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 299 insertions(+), 0 deletions(-) create mode 100755 scripts/tracetool.py 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() + -- 1.7.1.1