diff options
Diffstat (limited to 'scripts/tracetool')
-rw-r--r-- | scripts/tracetool/__init__.py | 105 | ||||
-rw-r--r-- | scripts/tracetool/format/events_h.py | 5 | ||||
-rw-r--r-- | scripts/tracetool/format/simpletrace_stap.py | 71 | ||||
-rw-r--r-- | scripts/tracetool/format/stap.py | 11 | ||||
-rw-r--r-- | scripts/tracetool/format/tcg_h.py | 57 | ||||
-rw-r--r-- | scripts/tracetool/format/tcg_helper_c.py | 50 | ||||
-rw-r--r-- | scripts/tracetool/format/tcg_helper_h.py | 50 | ||||
-rw-r--r-- | scripts/tracetool/format/tcg_helper_wrapper_h.py | 70 | ||||
-rw-r--r-- | scripts/tracetool/format/ust_events_h.py | 15 | ||||
-rw-r--r-- | scripts/tracetool/transform.py | 166 |
10 files changed, 586 insertions, 14 deletions
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index e8e8edcc4c..36c789de8f 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -15,9 +15,11 @@ __email__ = "stefanha@linux.vnet.ibm.com" import re import sys +import weakref import tracetool.format import tracetool.backend +import tracetool.transform def error_write(*lines): @@ -108,6 +110,18 @@ class Arguments: """List of argument types.""" return [ type_ for type_, _ in self._args ] + def transform(self, *trans): + """Return a new Arguments instance with transformed types. + + The types in the resulting Arguments instance are transformed according + to tracetool.transform.transform_type. + """ + res = [] + for type_, name in self._args: + res.append((tracetool.transform.transform_type(type_, *trans), + name)) + return Arguments(res) + class Event(object): """Event description. @@ -122,13 +136,21 @@ class Event(object): Properties of the event. args : Arguments The event arguments. + arg_fmts : str + The format strings for each argument. """ - _CRE = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?") + _CRE = re.compile("((?P<props>.*)\s+)?" + "(?P<name>[^(\s]+)" + "\((?P<args>[^)]*)\)" + "\s*" + "(?:(?:(?P<fmt_trans>\".+),)?\s*(?P<fmt>\".+))?" + "\s*") + _FMT = re.compile("(%\w+|%.*PRI\S+)") - _VALID_PROPS = set(["disable"]) + _VALID_PROPS = set(["disable", "tcg", "tcg-trans", "tcg-exec"]) - def __init__(self, name, props, fmt, args): + def __init__(self, name, props, fmt, args, arg_fmts, orig=None): """ Parameters ---------- @@ -136,20 +158,32 @@ class Event(object): Event name. props : list of str Property names. - fmt : str - Event printing format. + fmt : str, list of str + Event printing format (or formats). args : Arguments Event arguments. + arg_fmts : list of str + Format strings for each argument. + orig : Event or None + Original Event before transformation. + """ self.name = name self.properties = props self.fmt = fmt self.args = args + self.arg_fmts = arg_fmts + + if orig is None: + self.original = weakref.ref(self) + else: + self.original = orig unknown_props = set(self.properties) - self._VALID_PROPS if len(unknown_props) > 0: raise ValueError("Unknown properties: %s" % ", ".join(unknown_props)) + assert isinstance(self.fmt, str) or len(self.fmt) == 2 def copy(self): """Create a new copy.""" @@ -172,24 +206,50 @@ class Event(object): name = groups["name"] props = groups["props"].split() fmt = groups["fmt"] + fmt_trans = groups["fmt_trans"] + if len(fmt_trans) > 0: + fmt = [fmt_trans, fmt] args = Arguments.build(groups["args"]) + arg_fmts = Event._FMT.findall(fmt) + + if "tcg-trans" in props: + raise ValueError("Invalid property 'tcg-trans'") + if "tcg-exec" in props: + raise ValueError("Invalid property 'tcg-exec'") + if "tcg" not in props and not isinstance(fmt, str): + raise ValueError("Only events with 'tcg' property can have two formats") + if "tcg" in props and isinstance(fmt, str): + raise ValueError("Events with 'tcg' property must have two formats") - return Event(name, props, fmt, args) + return Event(name, props, fmt, args, arg_fmts) def __repr__(self): """Evaluable string representation for this object.""" + if isinstance(self.fmt, str): + fmt = self.fmt + else: + fmt = "%s, %s" % (self.fmt[0], self.fmt[1]) return "Event('%s %s(%s) %s')" % (" ".join(self.properties), self.name, self.args, - self.fmt) + fmt) QEMU_TRACE = "trace_%(name)s" + QEMU_TRACE_TCG = QEMU_TRACE + "_tcg" def api(self, fmt=None): if fmt is None: fmt = Event.QEMU_TRACE return fmt % {"name": self.name} + def transform(self, *trans): + """Return a new Event with transformed Arguments.""" + return Event(self.name, + list(self.properties), + self.fmt, + self.args.transform(*trans), + self) + def _read_events(fobj): res = [] @@ -272,4 +332,35 @@ def generate(fevents, format, backends, events = _read_events(fevents) + # transform TCG-enabled events + new_events = [] + for event in events: + if "tcg" not in event.properties: + new_events.append(event) + else: + event_trans = event.copy() + event_trans.name += "_trans" + event_trans.properties += ["tcg-trans"] + event_trans.fmt = event.fmt[0] + args_trans = [] + for atrans, aorig in zip( + event_trans.transform(tracetool.transform.TCG_2_HOST).args, + event.args): + if atrans == aorig: + args_trans.append(atrans) + event_trans.args = Arguments(args_trans) + event_trans = event_trans.copy() + + event_exec = event.copy() + event_exec.name += "_exec" + event_exec.properties += ["tcg-exec"] + event_exec.fmt = event.fmt[1] + event_exec = event_exec.transform(tracetool.transform.TCG_2_HOST) + + new_event = [event_trans, event_exec] + event.event_trans, event.event_exec = new_event + + new_events.extend(new_event) + events = new_events + tracetool.format.generate(events, format, backend) diff --git a/scripts/tracetool/format/events_h.py b/scripts/tracetool/format/events_h.py index 25d913bb25..9f114a3497 100644 --- a/scripts/tracetool/format/events_h.py +++ b/scripts/tracetool/format/events_h.py @@ -40,6 +40,11 @@ def generate(events, backend): enabled = 0 else: enabled = 1 + if "tcg-trans" in e.properties: + # a single define for the two "sub-events" + out('#define TRACE_%(name)s_ENABLED %(enabled)d', + name=e.original.original.name.upper(), + enabled=enabled) out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled)) out('#include "trace/event-internal.h"', diff --git a/scripts/tracetool/format/simpletrace_stap.py b/scripts/tracetool/format/simpletrace_stap.py new file mode 100644 index 0000000000..7e44bc1811 --- /dev/null +++ b/scripts/tracetool/format/simpletrace_stap.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate .stp file that outputs simpletrace binary traces (DTrace with SystemTAP only). +""" + +__author__ = "Stefan Hajnoczi <redhat.com>" +__copyright__ = "Copyright (C) 2014, Red Hat, Inc." +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@redhat.com" + + +from tracetool import out +from tracetool.backend.dtrace import binary, probeprefix +from tracetool.backend.simple import is_string +from tracetool.format.stap import stap_escape + + +def generate(events, backend): + out('/* This file is autogenerated by tracetool, do not edit. */', + '') + + for event_id, e in enumerate(events): + if 'disable' in e.properties: + continue + + out('probe %(probeprefix)s.simpletrace.%(name)s = %(probeprefix)s.%(name)s ?', + '{', + probeprefix=probeprefix(), + name=e.name) + + # Calculate record size + sizes = ['24'] # sizeof(TraceRecord) + for type_, name in e.args: + name = stap_escape(name) + if is_string(type_): + out(' try {', + ' arg%(name)s_str = %(name)s ? user_string_n(%(name)s, 512) : "<null>"', + ' } catch {}', + ' arg%(name)s_len = strlen(arg%(name)s_str)', + name=name) + sizes.append('4 + arg%s_len' % name) + else: + sizes.append('8') + sizestr = ' + '.join(sizes) + + # Generate format string and value pairs for record header and arguments + fields = [('8b', str(event_id)), + ('8b', 'gettimeofday_ns()'), + ('4b', sizestr), + ('4b', 'pid()')] + for type_, name in e.args: + name = stap_escape(name) + if is_string(type_): + fields.extend([('4b', 'arg%s_len' % name), + ('.*s', 'arg%s_len, arg%s_str' % (name, name))]) + else: + fields.append(('8b', name)) + + # Emit the entire record in a single SystemTap printf() + fmt_str = '%'.join(fmt for fmt, _ in fields) + arg_str = ', '.join(arg for _, arg in fields) + out(' printf("%%%(fmt_str)s", %(arg_str)s)', + fmt_str=fmt_str, arg_str=arg_str) + + out('}') + + out() diff --git a/scripts/tracetool/format/stap.py b/scripts/tracetool/format/stap.py index e24abf7f11..9e780f1b06 100644 --- a/scripts/tracetool/format/stap.py +++ b/scripts/tracetool/format/stap.py @@ -27,6 +27,13 @@ RESERVED_WORDS = ( ) +def stap_escape(identifier): + # Append underscore to reserved keywords + if identifier in RESERVED_WORDS: + return identifier + '_' + return identifier + + def generate(events, backend): events = [e for e in events if "disable" not in e.properties] @@ -45,9 +52,7 @@ def generate(events, backend): i = 1 if len(e.args) > 0: for name in e.args.names(): - # Append underscore to reserved keywords - if name in RESERVED_WORDS: - name += '_' + name = stap_escape(name) out(' %s = $arg%d;' % (name, i)) i += 1 diff --git a/scripts/tracetool/format/tcg_h.py b/scripts/tracetool/format/tcg_h.py new file mode 100644 index 0000000000..f676b66622 --- /dev/null +++ b/scripts/tracetool/format/tcg_h.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate .h file for TCG code generation. +""" + +__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +from tracetool import out + + +def generate(events, backend): + out('/* This file is autogenerated by tracetool, do not edit. */', + '/* You must include this file after the inclusion of helper.h */', + '', + '#ifndef TRACE__GENERATED_TCG_TRACERS_H', + '#define TRACE__GENERATED_TCG_TRACERS_H', + '', + '#include <stdint.h>', + '', + '#include "trace.h"', + '#include "exec/helper-proto.h"', + '', + ) + + for e in events: + # just keep one of them + if "tcg-trans" not in e.properties: + continue + + # get the original event definition + e = e.original.original + + out('static inline void %(name_tcg)s(%(args)s)', + '{', + name_tcg=e.api(e.QEMU_TRACE_TCG), + args=e.args) + + if "disable" not in e.properties: + out(' %(name_trans)s(%(argnames_trans)s);', + ' gen_helper_%(name_exec)s(%(argnames_exec)s);', + name_trans=e.event_trans.api(e.QEMU_TRACE), + name_exec=e.event_exec.api(e.QEMU_TRACE), + argnames_trans=", ".join(e.event_trans.args.names()), + argnames_exec=", ".join(e.event_exec.args.names())) + + out('}') + + out('', + '#endif /* TRACE__GENERATED_TCG_TRACERS_H */') diff --git a/scripts/tracetool/format/tcg_helper_c.py b/scripts/tracetool/format/tcg_helper_c.py new file mode 100644 index 0000000000..96655a0590 --- /dev/null +++ b/scripts/tracetool/format/tcg_helper_c.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate trace/generated-helpers.c. +""" + +__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +from tracetool import out +from tracetool.transform import * + + +def generate(events, backend): + events = [e for e in events + if "disable" not in e.properties] + + out('/* This file is autogenerated by tracetool, do not edit. */', + '', + '#include "qemu-common.h"', + '#include "trace.h"', + '#include "exec/helper-proto.h"', + '', + ) + + for e in events: + if "tcg-exec" not in e.properties: + continue + + # tracetool.generate always transforms types to host + e_args = e.original.args + + values = ["(%s)%s" % (t, n) + for t, n in e.args.transform(TCG_2_TCG_HELPER_DEF)] + + out('void %(name_tcg)s(%(args)s)', + '{', + ' %(name)s(%(values)s);', + '}', + name_tcg="helper_%s_proxy" % e.api(), + name=e.api(), + args=e_args.transform(HOST_2_TCG_COMPAT, TCG_2_TCG_HELPER_DEF), + values=", ".join(values), + ) diff --git a/scripts/tracetool/format/tcg_helper_h.py b/scripts/tracetool/format/tcg_helper_h.py new file mode 100644 index 0000000000..a8ba7ba8e3 --- /dev/null +++ b/scripts/tracetool/format/tcg_helper_h.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate trace/generated-helpers.h. +""" + +__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +from tracetool import out +from tracetool.transform import * + + +def generate(events, backend): + events = [e for e in events + if "disable" not in e.properties] + + out('/* This file is autogenerated by tracetool, do not edit. */', + '', + ) + + for e in events: + if "tcg-exec" not in e.properties: + continue + + # tracetool.generate always transforms types to host + e_args = e.original.args + + # TCG helper proxy declaration + fmt = "DEF_HELPER_FLAGS_%(argc)d(%(name)s, %(flags)svoid%(types)s)" + args = e_args.transform(HOST_2_TCG_COMPAT, HOST_2_TCG, + TCG_2_TCG_HELPER_DECL) + types = ", ".join(args.types()) + if types != "": + types = ", " + types + + flags = "TCG_CALL_NO_RWG, " + + out(fmt, + flags=flags, + argc=len(args), + name=e.api() + "_proxy", + types=types, + ) diff --git a/scripts/tracetool/format/tcg_helper_wrapper_h.py b/scripts/tracetool/format/tcg_helper_wrapper_h.py new file mode 100644 index 0000000000..cac5a878f9 --- /dev/null +++ b/scripts/tracetool/format/tcg_helper_wrapper_h.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate trace/generated-helpers-wrappers.h. +""" + +__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +from tracetool import out +from tracetool.transform import * + + +def generate(events, backend): + events = [e for e in events + if "disable" not in e.properties] + + out('/* This file is autogenerated by tracetool, do not edit. */', + '', + '#define tcg_temp_new_nop(v) (v)', + '#define tcg_temp_free_nop(v)', + '', + ) + + for e in events: + if "tcg-exec" not in e.properties: + continue + + # tracetool.generate always transforms types to host + e_args = e.original.args + + # mixed-type to TCG helper bridge + args_tcg_compat = e_args.transform(HOST_2_TCG_COMPAT) + + code_new = [ + "%(tcg_type)s __%(name)s = %(tcg_func)s(%(name)s);" % + {"tcg_type": transform_type(type_, HOST_2_TCG), + "tcg_func": transform_type(type_, HOST_2_TCG_TMP_NEW), + "name": name} + for (type_, name) in args_tcg_compat + ] + + code_free = [ + "%(tcg_func)s(__%(name)s);" % + {"tcg_func": transform_type(type_, HOST_2_TCG_TMP_FREE), + "name": name} + for (type_, name) in args_tcg_compat + ] + + gen_name = "gen_helper_" + e.api() + + out('static inline void %(name)s(%(args)s)', + '{', + ' %(code_new)s', + ' %(proxy_name)s(%(tmp_names)s);', + ' %(code_free)s', + '}', + name=gen_name, + args=e_args, + proxy_name=gen_name + "_proxy", + code_new="\n ".join(code_new), + code_free="\n ".join(code_free), + tmp_names=", ".join(["__%s" % name for _, name in e_args]), + ) diff --git a/scripts/tracetool/format/ust_events_h.py b/scripts/tracetool/format/ust_events_h.py index 5102565470..d18989942a 100644 --- a/scripts/tracetool/format/ust_events_h.py +++ b/scripts/tracetool/format/ust_events_h.py @@ -63,13 +63,20 @@ def generate(events, backend): name=e.name, args=", ".join(", ".join(i) for i in e.args)) - for t, n in e.args: - if ('int' in t) or ('long' in t) or ('unsigned' in t) or ('size_t' in t): + types = e.args.types() + names = e.args.names() + fmts = e.arg_fmts + for t,n,f in zip(types, names, fmts): + if ('char *' in t) or ('char*' in t): + out(' ctf_string(' + n + ', ' + n + ')') + elif ("%p" in f) or ("x" in f) or ("PRIx" in f): + out(' ctf_integer_hex('+ t + ', ' + n + ', ' + n + ')') + elif ("ptr" in t) or ("*" in t): + out(' ctf_integer_hex('+ t + ', ' + n + ', ' + n + ')') + elif ('int' in t) or ('long' in t) or ('unsigned' in t) or ('size_t' in t): out(' ctf_integer(' + t + ', ' + n + ', ' + n + ')') elif ('double' in t) or ('float' in t): out(' ctf_float(' + t + ', ' + n + ', ' + n + ')') - elif ('char *' in t) or ('char*' in t): - out(' ctf_string(' + n + ', ' + n + ')') elif ('void *' in t) or ('void*' in t): out(' ctf_integer_hex(unsigned long, ' + n + ', ' + n + ')') diff --git a/scripts/tracetool/transform.py b/scripts/tracetool/transform.py new file mode 100644 index 0000000000..fc5e679ed4 --- /dev/null +++ b/scripts/tracetool/transform.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Type-transformation rules. +""" + +__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +def _transform_type(type_, trans): + if isinstance(trans, str): + return trans + elif isinstance(trans, dict): + if type_ in trans: + return _transform_type(type_, trans[type_]) + elif None in trans: + return _transform_type(type_, trans[None]) + else: + return type_ + elif callable(trans): + return trans(type_) + else: + raise ValueError("Invalid type transformation rule: %s" % trans) + + +def transform_type(type_, *trans): + """Return a new type transformed according to the given rules. + + Applies each of the transformation rules in trans in order. + + If an element of trans is a string, return it. + + If an element of trans is a function, call it with type_ as its only + argument. + + If an element of trans is a dict, search type_ in its keys. If type_ is + a key, use the value as a transformation rule for type_. Otherwise, if + None is a key use the value as a transformation rule for type_. + + Otherwise, return type_. + + Parameters + ---------- + type_ : str + Type to transform. + trans : list of function or dict + Type transformation rules. + """ + if len(trans) == 0: + raise ValueError + res = type_ + for t in trans: + res = _transform_type(res, t) + return res + + +################################################## +# tcg -> host + +def _tcg_2_host(type_): + if type_ == "TCGv": + # force a fixed-size type (target-independent) + return "uint64_t" + else: + return type_ + +TCG_2_HOST = { + "TCGv_i32": "uint32_t", + "TCGv_i64": "uint64_t", + "TCGv_ptr": "void *", + None: _tcg_2_host, + } + + +################################################## +# host -> host compatible with tcg sizes + +HOST_2_TCG_COMPAT = { + "uint8_t": "uint32_t", + } + + +################################################## +# host/tcg -> tcg + +def _host_2_tcg(type_): + if type_.startswith("TCGv"): + return type_ + raise ValueError("Don't know how to translate '%s' into a TCG type\n" % type_) + +HOST_2_TCG = { + "uint32_t": "TCGv_i32", + "uint64_t": "TCGv_i64", + "void *" : "TCGv_ptr", + None: _host_2_tcg, + } + + +################################################## +# tcg -> tcg helper definition + +def _tcg_2_helper_def(type_): + if type_ == "TCGv": + return "target_ulong" + else: + return type_ + +TCG_2_TCG_HELPER_DEF = { + "TCGv_i32": "uint32_t", + "TCGv_i64": "uint64_t", + "TCGv_ptr": "void *", + None: _tcg_2_helper_def, + } + + +################################################## +# tcg -> tcg helper declaration + +def _tcg_2_tcg_helper_decl_error(type_): + raise ValueError("Don't know how to translate type '%s' into a TCG helper declaration type\n" % type_) + +TCG_2_TCG_HELPER_DECL = { + "TCGv" : "tl", + "TCGv_ptr": "ptr", + "TCGv_i32": "i32", + "TCGv_i64": "i64", + None: _tcg_2_tcg_helper_decl_error, + } + + +################################################## +# host/tcg -> tcg temporal constant allocation + +def _host_2_tcg_tmp_new(type_): + if type_.startswith("TCGv"): + return "tcg_temp_new_nop" + raise ValueError("Don't know how to translate type '%s' into a TCG temporal allocation" % type_) + +HOST_2_TCG_TMP_NEW = { + "uint32_t": "tcg_const_i32", + "uint64_t": "tcg_const_i64", + "void *" : "tcg_const_ptr", + None: _host_2_tcg_tmp_new, + } + + +################################################## +# host/tcg -> tcg temporal constant deallocation + +def _host_2_tcg_tmp_free(type_): + if type_.startswith("TCGv"): + return "tcg_temp_free_nop" + raise ValueError("Don't know how to translate type '%s' into a TCG temporal deallocation" % type_) + +HOST_2_TCG_TMP_FREE = { + "uint32_t": "tcg_temp_free_i32", + "uint64_t": "tcg_temp_free_i64", + "void *" : "tcg_temp_free_ptr", + None: _host_2_tcg_tmp_free, + } |