From a76ccf3c1cb06576af091c5ac8bc264515b1bb7f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 22 Jun 2014 21:46:04 +0800 Subject: trace: extract stap_escape() function for reuse SystemTap reserved words sometimes conflict with QEMU variable names. We escape them to prevent conflicts. Move escaping into its own function so the next patch can reuse it. Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/format/stap.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'scripts') 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 -- cgit v1.2.3-55-g7522 From 3f8b112d6b9ab65e165096582c78154dda1adc69 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 22 Jun 2014 21:46:05 +0800 Subject: trace: add tracetool simpletrace_stap format This new tracetool "format" generates a SystemTap .stp file that outputs simpletrace binary trace data. In contrast to simpletrace or ftrace, SystemTap does not define its own trace format. All output from SystemTap is generated by .stp files. This patch lets us generate a .stp file that outputs in the simpletrace binary format. This makes it possible to reuse simpletrace.py to analyze traces recorded using SystemTap. The simpletrace binary format is especially useful for long-running traces like flight-recorder mode where string formatting can be expensive. Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/format/simpletrace_stap.py | 71 ++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 scripts/tracetool/format/simpletrace_stap.py (limited to 'scripts') 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 " +__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) : ""', + ' } 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() -- cgit v1.2.3-55-g7522 From 15327c3df049c9621ff9b542ccbfc3d17203d1f7 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 22 Jun 2014 21:46:06 +0800 Subject: simpletrace: add simpletrace.py --no-header option It can be useful to read simpletrace files that have no header. For example, a ring buffer may not have a header record but can still be processed if the user is sure the file format version is compatible. $ scripts/simpletrace.py --no-header trace-events trace-file Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'scripts') diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 1aa9460e49..3916c6d14a 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -58,8 +58,8 @@ def read_record(edict, fobj): rechdr = read_header(fobj, rec_header_fmt) return get_record(edict, rechdr, fobj) # return tuple of record elements -def read_trace_file(edict, fobj): - """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, pid, arg1, ..., arg6).""" +def read_trace_header(fobj): + """Read and verify trace file header""" header = read_header(fobj, log_header_fmt) if header is None or \ header[0] != header_event_id or \ @@ -73,6 +73,8 @@ def read_trace_file(edict, fobj): raise ValueError('Log format %d not supported with this QEMU release!' % log_version) +def read_trace_records(edict, fobj): + """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, pid, arg1, ..., arg6).""" while True: rec = read_record(edict, fobj) if rec is None: @@ -102,13 +104,16 @@ class Analyzer(object): """Called at the end of the trace.""" pass -def process(events, log, analyzer): +def process(events, log, analyzer, read_header=True): """Invoke an analyzer on each event in a log.""" if isinstance(events, str): events = _read_events(open(events, 'r')) if isinstance(log, str): log = open(log, 'rb') + if read_header: + read_trace_header(log) + dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)") edict = {dropped_event_id: dropped_event} @@ -137,7 +142,7 @@ def process(events, log, analyzer): analyzer.begin() fn_cache = {} - for rec in read_trace_file(edict, log): + for rec in read_trace_records(edict, log): event_num = rec[0] event = edict[event_num] if event_num not in fn_cache: @@ -152,12 +157,17 @@ def run(analyzer): advanced scripts will want to call process() instead.""" import sys - if len(sys.argv) != 3: - sys.stderr.write('usage: %s \n' % sys.argv[0]) + read_header = True + if len(sys.argv) == 4 and sys.argv[1] == '--no-header': + read_header = False + del sys.argv[1] + elif len(sys.argv) != 3: + sys.stderr.write('usage: %s [--no-header] ' \ + '\n' % sys.argv[0]) sys.exit(1) events = _read_events(open(sys.argv[1], 'r')) - process(events, sys.argv[2], analyzer) + process(events, sys.argv[2], analyzer, read_header=read_header) if __name__ == '__main__': class Formatter(Analyzer): -- cgit v1.2.3-55-g7522 From e6d6c4bebf493317deec329069b7e872c2237684 Mon Sep 17 00:00:00 2001 From: Lluís Vilanova Date: Fri, 30 May 2014 14:11:32 +0200 Subject: trace: [tcg] Argument type transformation rules Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/transform.py | 166 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 scripts/tracetool/transform.py (limited to 'scripts') 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 " +__copyright__ = "Copyright 2012-2014, Lluís Vilanova " +__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, + } -- cgit v1.2.3-55-g7522 From b55835ac109b7f5f11a3f12bf445f75b76bc9f01 Mon Sep 17 00:00:00 2001 From: Lluís Vilanova Date: Fri, 30 May 2014 14:11:38 +0200 Subject: trace: [tcg] Argument type transformation machinery Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/__init__.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index e8e8edcc4c..bd3fd85d78 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -15,6 +15,7 @@ __email__ = "stefanha@linux.vnet.ibm.com" import re import sys +import weakref import tracetool.format import tracetool.backend @@ -108,6 +109,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. @@ -128,7 +141,7 @@ class Event(object): _VALID_PROPS = set(["disable"]) - def __init__(self, name, props, fmt, args): + def __init__(self, name, props, fmt, args, orig=None): """ Parameters ---------- @@ -140,12 +153,19 @@ class Event(object): Event printing format. args : Arguments Event arguments. + orig : Event or None + Original Event before transformation. """ self.name = name self.properties = props self.fmt = fmt self.args = args + 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" @@ -190,6 +210,14 @@ class Event(object): 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 = [] -- cgit v1.2.3-55-g7522 From b2b36c22bd8b14de34bd108daa96d89ba41fe8e7 Mon Sep 17 00:00:00 2001 From: Lluís Vilanova Date: Fri, 30 May 2014 14:11:44 +0200 Subject: trace: [tcg] Add 'tcg' event property Transforms event: tcg name(...) "...", "..." into two internal events: tcg-trans name_trans(...) "..." tcg-exec name_exec(...) "..." Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/__init__.py | 64 +++++++++++++++++++++++++++++++++--- scripts/tracetool/format/events_h.py | 5 +++ 2 files changed, 64 insertions(+), 5 deletions(-) (limited to 'scripts') diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index bd3fd85d78..de48c80c13 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -19,6 +19,7 @@ import weakref import tracetool.format import tracetool.backend +import tracetool.transform def error_write(*lines): @@ -137,9 +138,14 @@ class Event(object): The event arguments. """ - _CRE = re.compile("((?P.*)\s+)?(?P[^(\s]+)\((?P[^)]*)\)\s*(?P\".*)?") + _CRE = re.compile("((?P.*)\s+)?" + "(?P[^(\s]+)" + "\((?P[^)]*)\)" + "\s*" + "(?:(?:(?P\".+),)?\s*(?P\".+))?" + "\s*") - _VALID_PROPS = set(["disable"]) + _VALID_PROPS = set(["disable", "tcg", "tcg-trans", "tcg-exec"]) def __init__(self, name, props, fmt, args, orig=None): """ @@ -149,8 +155,8 @@ 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. orig : Event or None @@ -170,6 +176,7 @@ class Event(object): 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.""" @@ -192,16 +199,32 @@ 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"]) + 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) 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" @@ -300,4 +323,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"', -- cgit v1.2.3-55-g7522 From 707c8a98e4c42a559ad8d1ec0e77e28ffd666346 Mon Sep 17 00:00:00 2001 From: Lluís Vilanova Date: Fri, 30 May 2014 14:11:50 +0200 Subject: trace: [tcg] Declare TCG tracing helper routines Generates file "trace/generated-helpers.h" with TCG helper declarations to trace events in guest code at execution time ('trace_${event}_exec_proxy'). Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- .gitignore | 1 + Makefile | 2 ++ scripts/tracetool/__init__.py | 1 + scripts/tracetool/format/tcg_helper_h.py | 50 ++++++++++++++++++++++++++++++++ trace/Makefile.objs | 24 +++++++++++---- 5 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 scripts/tracetool/format/tcg_helper_h.py (limited to 'scripts') diff --git a/.gitignore b/.gitignore index 2286d0a109..da56d700c8 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /trace/generated-tracers.dtrace /trace/generated-events.h /trace/generated-events.c +/trace/generated-helpers.h /trace/generated-ust-provider.h /trace/generated-ust.c /libcacard/trace/generated-tracers.c diff --git a/Makefile b/Makefile index d6b9dc1ebe..84e9ad4a06 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,8 @@ GENERATED_HEADERS += trace/generated-tracers-dtrace.h endif GENERATED_SOURCES += trace/generated-tracers.c +GENERATED_HEADERS += trace/generated-helpers.h + ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust) GENERATED_HEADERS += trace/generated-ust-provider.h GENERATED_SOURCES += trace/generated-ust.c diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index de48c80c13..a51e0f24d7 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -227,6 +227,7 @@ class Event(object): fmt) QEMU_TRACE = "trace_%(name)s" + QEMU_TRACE_TCG = QEMU_TRACE + "_tcg" def api(self, fmt=None): if fmt is None: 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 " +__copyright__ = "Copyright 2012-2014, Lluís Vilanova " +__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/trace/Makefile.objs b/trace/Makefile.objs index d7a86969a4..0a2e6cd71c 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -49,6 +49,9 @@ util-obj-y += generated-events.o ###################################################################### # Auto-generated tracing routines +################################################## +# Execution level + $(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp @cmp -s $< $@ || cp $< $@ $(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak @@ -57,8 +60,8 @@ $(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf --backends=$(TRACE_BACKENDS) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") -###################################################################### -# Auto-generated tracing routines (non-DTrace) +############################## +# non-DTrace $(obj)/generated-tracers.c: $(obj)/generated-tracers.c-timestamp @cmp -s $< $@ || cp $< $@ @@ -70,9 +73,8 @@ $(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h - -###################################################################### -# Auto-generated DTrace code +############################## +# DTrace # Normal practice is to name DTrace probe file with a '.d' extension # but that gets picked up by QEMU's Makefile as an external dependency @@ -94,6 +96,18 @@ $(obj)/generated-tracers-dtrace.o: $(obj)/generated-tracers-dtrace.dtrace util-obj-y += generated-tracers-dtrace.o endif +################################################## +# Translation level + +$(obj)/generated-helpers.h: $(obj)/generated-helpers.h-timestamp +$(obj)/generated-helpers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=tcg-helper-h \ + --backend=$(TRACE_BACKENDS) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + + ###################################################################### # Backend code -- cgit v1.2.3-55-g7522 From 341ea69185239eeb7da73434ac2803790a429e9c Mon Sep 17 00:00:00 2001 From: Lluís Vilanova Date: Fri, 30 May 2014 14:11:56 +0200 Subject: trace: [tcg] Define TCG tracing helper routines Generates file "trace/generated-helpers.c" with TCG helper definitions to trace events in guest code at execution time. The helpers ('helper_trace_${event}_exec_proxy') cast the TCG-compatible native argument types to their original types (as defined in "trace-events") and call the tracing routine ('trace_${event}_exec'). Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- .gitignore | 1 + Makefile | 1 + Makefile.objs | 7 ++++- Makefile.target | 5 ++++ scripts/tracetool/format/tcg_helper_c.py | 50 ++++++++++++++++++++++++++++++++ trace/Makefile.objs | 12 ++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 scripts/tracetool/format/tcg_helper_c.py (limited to 'scripts') diff --git a/.gitignore b/.gitignore index da56d700c8..643b34b235 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ /trace/generated-events.h /trace/generated-events.c /trace/generated-helpers.h +/trace/generated-helpers.c /trace/generated-ust-provider.h /trace/generated-ust.c /libcacard/trace/generated-tracers.c diff --git a/Makefile b/Makefile index 84e9ad4a06..09601f7d27 100644 --- a/Makefile +++ b/Makefile @@ -58,6 +58,7 @@ endif GENERATED_SOURCES += trace/generated-tracers.c GENERATED_HEADERS += trace/generated-helpers.h +GENERATED_SOURCES += trace/generated-helpers.c ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust) GENERATED_HEADERS += trace/generated-ust-provider.h diff --git a/Makefile.objs b/Makefile.objs index 1f76cea569..84b86af879 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -1,7 +1,7 @@ ####################################################################### # Common libraries for tools and emulators stub-obj-y = stubs/ -util-obj-y = util/ qobject/ qapi/ trace/ +util-obj-y = util/ qobject/ qapi/ ####################################################################### # block-obj-y is code used by both qemu system emulation and qemu-img @@ -106,6 +106,11 @@ common-obj-y += disas/ version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o version-lobj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.lo +###################################################################### +# tracing +util-obj-y += trace/ +target-obj-y += trace/ + ###################################################################### # guest agent diff --git a/Makefile.target b/Makefile.target index 44fa6a2d5c..1e8d7abcb3 100644 --- a/Makefile.target +++ b/Makefile.target @@ -159,15 +159,20 @@ endif # CONFIG_SOFTMMU dummy := $(call unnest-vars,,obj-y) all-obj-y := $(obj-y) +target-obj-y := block-obj-y := common-obj-y := include $(SRC_PATH)/Makefile.objs +dummy := $(call unnest-vars,,target-obj-y) +target-obj-y-save := $(target-obj-y) dummy := $(call unnest-vars,.., \ block-obj-y \ block-obj-m \ common-obj-y \ common-obj-m) +target-obj-y := $(target-obj-y-save) all-obj-y += $(common-obj-y) +all-obj-y += $(target-obj-y) all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) # build either PROG or PROGW 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 " +__copyright__ = "Copyright 2012-2014, Lluís Vilanova " +__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/trace/Makefile.objs b/trace/Makefile.objs index 0a2e6cd71c..2d36142df0 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -107,6 +107,18 @@ $(obj)/generated-helpers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) +$(obj)/generated-helpers.c: $(obj)/generated-helpers.c-timestamp +$(obj)/generated-helpers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=tcg-helper-c \ + --backend=$(TRACE_BACKENDS) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + +$(obj)/generated-helpers.o: $(obj)/generated-helpers.c + +target-obj-y += generated-helpers.o + ###################################################################### # Backend code -- cgit v1.2.3-55-g7522 From f4654226d42cff5351b5f0df5913c5cf04775cdc Mon Sep 17 00:00:00 2001 From: Lluís Vilanova Date: Fri, 30 May 2014 14:12:01 +0200 Subject: trace: [tcg] Define TCG tracing helper routine wrappers Generates header "trace/generated-helpers-wrappers.h" with definitions for TCG helper wrappers. These wrappers ('gen_helper_trace_${event}_exec_wrapper') transform mixed native and TCG argument types to TCG types and call the actual TCG helpers ('gen_helper_trace_${event}_exec_proxy'). Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- .gitignore | 1 + Makefile | 1 + scripts/tracetool/format/tcg_helper_wrapper_h.py | 70 ++++++++++++++++++++++++ trace/Makefile.objs | 8 +++ 4 files changed, 80 insertions(+) create mode 100644 scripts/tracetool/format/tcg_helper_wrapper_h.py (limited to 'scripts') diff --git a/.gitignore b/.gitignore index 643b34b235..6631c57b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /trace/generated-tracers.dtrace /trace/generated-events.h /trace/generated-events.c +/trace/generated-helpers-wrappers.h /trace/generated-helpers.h /trace/generated-helpers.c /trace/generated-ust-provider.h diff --git a/Makefile b/Makefile index 09601f7d27..fa93fc91c6 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,7 @@ GENERATED_HEADERS += trace/generated-tracers-dtrace.h endif GENERATED_SOURCES += trace/generated-tracers.c +GENERATED_HEADERS += trace/generated-helpers-wrappers.h GENERATED_HEADERS += trace/generated-helpers.h GENERATED_SOURCES += trace/generated-helpers.c 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 " +__copyright__ = "Copyright 2012-2014, Lluís Vilanova " +__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/trace/Makefile.objs b/trace/Makefile.objs index 2d36142df0..72cc3f57d1 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -99,6 +99,14 @@ endif ################################################## # Translation level +$(obj)/generated-helpers-wrappers.h: $(obj)/generated-helpers-wrappers.h-timestamp +$(obj)/generated-helpers-wrappers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=tcg-helper-wrapper-h \ + --backend=$(TRACE_BACKENDS) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + $(obj)/generated-helpers.h: $(obj)/generated-helpers.h-timestamp $(obj)/generated-helpers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ -- cgit v1.2.3-55-g7522 From 465830fbd9be22995b34d7b3f8cd35572e1f8a36 Mon Sep 17 00:00:00 2001 From: Lluís Vilanova Date: Fri, 30 May 2014 14:12:13 +0200 Subject: trace: [tcg] Generate TCG tracing routines Generate header "trace/generated-tcg-tracers.h" with the necessary routines for tracing events in guest code: * trace_${event}_tcg Convenience wrapper that calls the translation-time tracer 'trace_${event}_trans', and calls 'gen_helper_trace_${event}_exec to generate the TCG code to later trace the event at execution time. Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- .gitignore | 1 + Makefile | 2 ++ include/trace-tcg.h | 7 +++++ scripts/tracetool/format/tcg_h.py | 57 +++++++++++++++++++++++++++++++++++++++ trace/Makefile.objs | 9 +++++++ 5 files changed, 76 insertions(+) create mode 100644 include/trace-tcg.h create mode 100644 scripts/tracetool/format/tcg_h.py (limited to 'scripts') diff --git a/.gitignore b/.gitignore index 6631c57b8d..e32a58417a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ /trace/generated-helpers-wrappers.h /trace/generated-helpers.h /trace/generated-helpers.c +/trace/generated-tcg-tracers.h /trace/generated-ust-provider.h /trace/generated-ust.c /libcacard/trace/generated-tracers.c diff --git a/Makefile b/Makefile index fa93fc91c6..20b697ec4c 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,8 @@ GENERATED_HEADERS += trace/generated-tracers-dtrace.h endif GENERATED_SOURCES += trace/generated-tracers.c +GENERATED_HEADERS += trace/generated-tcg-tracers.h + GENERATED_HEADERS += trace/generated-helpers-wrappers.h GENERATED_HEADERS += trace/generated-helpers.h GENERATED_SOURCES += trace/generated-helpers.c diff --git a/include/trace-tcg.h b/include/trace-tcg.h new file mode 100644 index 0000000000..6f6bdbb44a --- /dev/null +++ b/include/trace-tcg.h @@ -0,0 +1,7 @@ +#ifndef TRACE_TCG_H +#define TRACE_TCG_H + +#include "trace/generated-tcg-tracers.h" +#include "trace/generated-events.h" + +#endif /* TRACE_TCG_H */ 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 " +__copyright__ = "Copyright 2012-2014, Lluís Vilanova " +__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 ', + '', + '#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/trace/Makefile.objs b/trace/Makefile.objs index 72cc3f57d1..387f191fd4 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -128,6 +128,15 @@ $(obj)/generated-helpers.o: $(obj)/generated-helpers.c target-obj-y += generated-helpers.o +$(obj)/generated-tcg-tracers.h: $(obj)/generated-tcg-tracers.h-timestamp +$(obj)/generated-tcg-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=tcg-h \ + --backend=$(TRACE_BACKENDS) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + + ###################################################################### # Backend code -- cgit v1.2.3-55-g7522 From 41ef7b00abff4d31814890a14e5a8e49a177508b Mon Sep 17 00:00:00 2001 From: Alex Bennée Date: Fri, 1 Aug 2014 17:08:56 +0100 Subject: trace: teach lttng backend to use format strings This makes the UST backend pay attention to the format string arguments that are defined when defining payload data. With this you can now ensure integers are reported in hex mode if you want. Signed-off-by: Alex Bennée Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/__init__.py | 12 ++++++++++-- scripts/tracetool/format/ust_events_h.py | 15 +++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'scripts') diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index a51e0f24d7..36c789de8f 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -136,6 +136,8 @@ 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.*)\s+)?" @@ -144,10 +146,11 @@ class Event(object): "\s*" "(?:(?:(?P\".+),)?\s*(?P\".+))?" "\s*") + _FMT = re.compile("(%\w+|%.*PRI\S+)") _VALID_PROPS = set(["disable", "tcg", "tcg-trans", "tcg-exec"]) - def __init__(self, name, props, fmt, args, orig=None): + def __init__(self, name, props, fmt, args, arg_fmts, orig=None): """ Parameters ---------- @@ -159,13 +162,17 @@ class Event(object): 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) @@ -203,6 +210,7 @@ class Event(object): 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'") @@ -213,7 +221,7 @@ class Event(object): 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.""" 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 + ')') -- cgit v1.2.3-55-g7522