From a76ccf3c1cb06576af091c5ac8bc264515b1bb7f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 22 Jun 2014 21:46:04 +0800 Subject: [PATCH 01/18] 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(-) 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 From 3f8b112d6b9ab65e165096582c78154dda1adc69 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 22 Jun 2014 21:46:05 +0800 Subject: [PATCH 02/18] 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 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() From 15327c3df049c9621ff9b542ccbfc3d17203d1f7 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 22 Jun 2014 21:46:06 +0800 Subject: [PATCH 03/18] 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(-) 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): From e0b2fd0efb4d282bc6fa0ed5397f472298a66ca2 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 22 Jun 2014 21:46:07 +0800 Subject: [PATCH 04/18] trace: install simpletrace SystemTap tapset The simpletrace SystemTap tapset outputs simpletrace binary traces for SystemTap probes. This is useful because SystemTap has no default way to format or store traces. The simpletrace SystemTap tapset provides an easy way to store traces. The simpletrace.py tool or custom Python scripts using the simpletrace.py API can analyze SystemTap these traces: $ ./configure --enable-trace-backends=dtrace ... $ make && make install $ stap -e 'probe qemu.system.x86_64.simpletrace.* {}' \ -c qemu-system-x86_64 >/tmp/trace.out $ scripts/simpletrace.py --no-header trace-events /tmp/trace.out g_malloc 4.531 pid=15519 size=0xb ptr=0x7f8639c10470 g_malloc 3.264 pid=15519 size=0x300 ptr=0x7f8639c10490 g_free 5.155 pid=15519 ptr=0x7f8639c0f7b0 Note that, unlike qemu-system-x86_64.stp and qemu-system-x86_64.stp-installed, only one file is needed since the simpletrace SystemTap tapset does not reference the QEMU binary by path. Therefore it doesn't matter whether the QEMU binary is installed or not. Signed-off-by: Stefan Hajnoczi --- Makefile.target | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 137d0b0517..44fa6a2d5c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -38,7 +38,7 @@ config-target.h: config-target.h-timestamp config-target.h-timestamp: config-target.mak ifdef CONFIG_TRACE_SYSTEMTAP -stap: $(QEMU_PROG).stp-installed $(QEMU_PROG).stp +stap: $(QEMU_PROG).stp-installed $(QEMU_PROG).stp $(QEMU_PROG)-simpletrace.stp ifdef CONFIG_USER_ONLY TARGET_TYPE=user @@ -64,6 +64,13 @@ $(QEMU_PROG).stp: $(SRC_PATH)/trace-events --target-type=$(TARGET_TYPE) \ < $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp") +$(QEMU_PROG)-simpletrace.stp: $(SRC_PATH)/trace-events + $(call quiet-command,$(TRACETOOL) \ + --format=simpletrace-stap \ + --backends=$(TRACE_BACKENDS) \ + --probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \ + < $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp") + else stap: endif @@ -191,6 +198,7 @@ endif ifdef CONFIG_TRACE_SYSTEMTAP $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset" $(INSTALL_DATA) $(QEMU_PROG).stp-installed "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG).stp" + $(INSTALL_DATA) $(QEMU_PROG)-simpletrace.stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG)-simpletrace.stp" endif GENERATED_HEADERS += config-target.h From 0bb403b0ae6f8805696a7e73138d93635bebc6f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 30 May 2014 14:11:26 +0200 Subject: [PATCH 05/18] trace: [tcg] Add documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- docs/tracing.txt | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/tracing.txt b/docs/tracing.txt index c6ab1c11c1..2e035a5b3c 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -307,3 +307,43 @@ guard such computations and avoid its compilation when the event is disabled: You can check both if the event has been disabled and is dynamically enabled at the same time using the 'trace_event_get_state' routine (see header "trace/control.h" for more information). + +=== "tcg" === + +Guest code generated by TCG can be traced by defining an event with the "tcg" +event property. Internally, this property generates two events: +"_trans" to trace the event at translation time, and +"_exec" to trace the event at execution time. + +Instead of using these two events, you should instead use the function +"trace__tcg" during translation (TCG code generation). This function +will automatically call "trace__trans", and will generate the +necessary TCG code to call "trace__exec" during guest code execution. + +Events with the "tcg" property can be declared in the "trace-events" file with a +mix of native and TCG types, and "trace__tcg" will gracefully forward +them to the "_trans" and "_exec" events. Since TCG values +are not known at translation time, these are ignored by the "_trans" +event. Because of this, the entry in the "trace-events" file needs two printing +formats (separated by a comma): + + tcg foo(uint8_t a1, TCGv_i32 a2) "a1=%d", "a1=%d a2=%d" + +For example: + + #include "trace-tcg.h" + + void some_disassembly_func (...) + { + uint8_t a1 = ...; + TCGv_i32 a2 = ...; + trace_foo_tcg(a1, a2); + } + +This will immediately call: + + void trace_foo_trans(uint8_t a1); + +and will generate the TCG code to call: + + void trace_foo(uint8_t a1, uint32_t a2); From e6d6c4bebf493317deec329069b7e872c2237684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 30 May 2014 14:11:32 +0200 Subject: [PATCH 06/18] trace: [tcg] Argument type transformation rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 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, + } From b55835ac109b7f5f11a3f12bf445f75b76bc9f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 30 May 2014 14:11:38 +0200 Subject: [PATCH 07/18] trace: [tcg] Argument type transformation machinery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/__init__.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) 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 = [] From b2b36c22bd8b14de34bd108daa96d89ba41fe8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 30 May 2014 14:11:44 +0200 Subject: [PATCH 08/18] trace: [tcg] Add 'tcg' event property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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(-) 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"', From 707c8a98e4c42a559ad8d1ec0e77e28ffd666346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 30 May 2014 14:11:50 +0200 Subject: [PATCH 09/18] trace: [tcg] Declare TCG tracing helper routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 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 From 341ea69185239eeb7da73434ac2803790a429e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 30 May 2014 14:11:56 +0200 Subject: [PATCH 10/18] trace: [tcg] Define TCG tracing helper routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 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 From f4654226d42cff5351b5f0df5913c5cf04775cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 30 May 2014 14:12:01 +0200 Subject: [PATCH 11/18] trace: [tcg] Define TCG tracing helper routine wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 + .../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 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) \ From 76b53aa32457e63957540d99149901989c075d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 30 May 2014 14:12:07 +0200 Subject: [PATCH 12/18] trace: [tcg] Include TCG-tracing helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- include/exec/helper-gen.h | 2 ++ include/exec/helper-proto.h | 1 + include/exec/helper-tcg.h | 1 + 3 files changed, 4 insertions(+) diff --git a/include/exec/helper-gen.h b/include/exec/helper-gen.h index a04a0341e2..0d0da3aeb3 100644 --- a/include/exec/helper-gen.h +++ b/include/exec/helper-gen.h @@ -57,6 +57,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \ } #include "helper.h" +#include "trace/generated-helpers.h" +#include "trace/generated-helpers-wrappers.h" #include "tcg-runtime.h" #undef DEF_HELPER_FLAGS_0 diff --git a/include/exec/helper-proto.h b/include/exec/helper-proto.h index 828951c609..effdd4383a 100644 --- a/include/exec/helper-proto.h +++ b/include/exec/helper-proto.h @@ -27,6 +27,7 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ dh_ctype(t4), dh_ctype(t5)); #include "helper.h" +#include "trace/generated-helpers.h" #include "tcg-runtime.h" #undef DEF_HELPER_FLAGS_0 diff --git a/include/exec/helper-tcg.h b/include/exec/helper-tcg.h index d704c81126..79fa3c8c81 100644 --- a/include/exec/helper-tcg.h +++ b/include/exec/helper-tcg.h @@ -36,6 +36,7 @@ | dh_sizemask(t5, 5) }, #include "helper.h" +#include "trace/generated-helpers.h" #include "tcg-runtime.h" #undef DEF_HELPER_FLAGS_0 From 465830fbd9be22995b34d7b3f8cd35572e1f8a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 30 May 2014 14:12:13 +0200 Subject: [PATCH 13/18] trace: [tcg] Generate TCG tracing routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 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 From 85d8bf2f36ae28b8d4b04f473886ce7f725a8b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 30 May 2014 14:12:19 +0200 Subject: [PATCH 14/18] trace: [tcg] Include event definitions in "trace.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise the user has to explicitly include an auto-generated header. Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- include/trace.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/trace.h b/include/trace.h index c15f498128..44a1f1f8c7 100644 --- a/include/trace.h +++ b/include/trace.h @@ -2,5 +2,6 @@ #define TRACE_H #include "trace/generated-tracers.h" +#include "trace/generated-events.h" #endif /* TRACE_H */ From a7e30d84ce8109b50ee73633f72802918836b19f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 30 May 2014 14:12:25 +0200 Subject: [PATCH 15/18] trace: [tcg] Include TCG-tracing header on all targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- target-alpha/translate.c | 3 +++ target-arm/translate-a64.c | 2 ++ target-arm/translate.c | 3 +++ target-cris/translate.c | 3 +++ target-i386/translate.c | 3 +++ target-lm32/translate.c | 3 +++ target-m68k/translate.c | 3 +++ target-microblaze/translate.c | 3 +++ target-mips/translate.c | 3 +++ target-openrisc/translate.c | 3 +++ target-ppc/translate.c | 3 +++ target-s390x/translate.c | 2 ++ target-sh4/translate.c | 3 +++ target-sparc/translate.c | 3 +++ target-unicore32/translate.c | 3 +++ target-xtensa/translate.c | 3 +++ 16 files changed, 46 insertions(+) diff --git a/target-alpha/translate.c b/target-alpha/translate.c index cc81e774df..76658a074a 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -26,6 +26,9 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + + #undef ALPHA_DEBUG_DISAS #define CONFIG_SOFTFLOAT_INLINE diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 33b5025fee..f04ca49631 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -35,6 +35,8 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + static TCGv_i64 cpu_X[32]; static TCGv_i64 cpu_pc; static TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF; diff --git a/target-arm/translate.c b/target-arm/translate.c index cf4e767ff8..40121858d6 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -35,6 +35,9 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + + #define ENABLE_ARCH_4T arm_feature(env, ARM_FEATURE_V4T) #define ENABLE_ARCH_5 arm_feature(env, ARM_FEATURE_V5) /* currently all emulated v5 cores are also v5TE, so don't bother */ diff --git a/target-cris/translate.c b/target-cris/translate.c index ab0e47962b..e37b04e69d 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -33,6 +33,9 @@ #include "exec/helper-gen.h" +#include "trace-tcg.h" + + #define DISAS_CRIS 0 #if DISAS_CRIS # define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) diff --git a/target-i386/translate.c b/target-i386/translate.c index 6fcd8245d2..418173e0ea 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -32,6 +32,9 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + + #define PREFIX_REPZ 0x01 #define PREFIX_REPNZ 0x02 #define PREFIX_LOCK 0x04 diff --git a/target-lm32/translate.c b/target-lm32/translate.c index a51ade9a15..8454e8b517 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -27,6 +27,9 @@ #include "exec/helper-gen.h" +#include "trace-tcg.h" + + #define DISAS_LM32 1 #if DISAS_LM32 # define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 50df4d3844..efd4cfc3c7 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -27,6 +27,9 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + + //#define DEBUG_DISPATCH 1 /* Fake floating point. */ diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 03ea15803b..fd2b771645 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -26,6 +26,9 @@ #include "exec/cpu_ldst.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + + #define SIM_COMPAT 0 #define DISAS_GNU 1 #define DISAS_MB 1 diff --git a/target-mips/translate.c b/target-mips/translate.c index c381366506..06db150325 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -30,6 +30,9 @@ #include "exec/helper-gen.h" #include "sysemu/kvm.h" +#include "trace-tcg.h" + + #define MIPS_DEBUG_DISAS 0 //#define MIPS_DEBUG_SIGN_EXTENSIONS diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c index 55ff935d5e..407bd9762f 100644 --- a/target-openrisc/translate.c +++ b/target-openrisc/translate.c @@ -31,6 +31,9 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + + #define OPENRISC_DISAS #ifdef OPENRISC_DISAS diff --git a/target-ppc/translate.c b/target-ppc/translate.c index b23933f7bd..c07bb01a7a 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -27,6 +27,9 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + + #define CPU_SINGLE_STEP 0x1 #define CPU_BRANCH_STEP 0x2 #define GDBSTUB_SINGLE_STEP 0x4 diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e2a1d05f15..0cb036f667 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -42,6 +42,8 @@ static TCGv_ptr cpu_env; #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + /* Information that (most) every instruction needs to manipulate. */ typedef struct DisasContext DisasContext; diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 8126818142..3088edc6a6 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -28,6 +28,9 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + + typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 1ab07a18a2..78c4e21cff 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -32,6 +32,9 @@ #include "exec/helper-gen.h" +#include "trace-tcg.h" + + #define DEBUG_DISAS #define DYNAMIC_PC 1 /* dynamic pc value */ diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index e3643c23cd..653c225187 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -23,6 +23,9 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + + /* internal defines */ typedef struct DisasContext { target_ulong pc; diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index 2f22cce845..badca195f4 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -41,6 +41,9 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + + typedef struct DisasContext { const XtensaConfig *config; TranslationBlock *tb; From 41ef7b00abff4d31814890a14e5a8e49a177508b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 1 Aug 2014 17:08:56 +0100 Subject: [PATCH 16/18] trace: teach lttng backend to use format strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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(-) 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 + ')') From 6db8b538663b39c21e12e14e6437aa7f8435f316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 1 Aug 2014 17:08:57 +0100 Subject: [PATCH 17/18] trace: add some tcg tracing support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a couple of tcg specific trace-events which are useful for tracing execution though tcg generated blocks. It's been tested with lttng user space tracing but is generic enough for all systems. The tcg events are: * translate_block - when a subject block is translated * exec_tb - when a translated block is entered * exec_tb_exit - when we exit the translated code * exec_tb_nocache - special case translations Of course we can only trace the entrance to the first block of a chain as each block will jump directly to the next when it can. See the -d nochain patch to allow more complete tracing at the expense of performance. Signed-off-by: Alex Bennée Signed-off-by: Stefan Hajnoczi --- cpu-exec.c | 6 ++++++ trace-events | 9 +++++++++ translate-all.c | 3 +++ 3 files changed, 18 insertions(+) diff --git a/cpu-exec.c b/cpu-exec.c index cbc8067b37..c6aad742e1 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -18,6 +18,7 @@ */ #include "config.h" #include "cpu.h" +#include "trace.h" #include "disas/disas.h" #include "tcg.h" #include "qemu/atomic.h" @@ -168,6 +169,9 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr) #endif /* DEBUG_DISAS */ next_tb = tcg_qemu_tb_exec(env, tb_ptr); + trace_exec_tb_exit((void *) (next_tb & ~TB_EXIT_MASK), + next_tb & TB_EXIT_MASK); + if ((next_tb & TB_EXIT_MASK) > TB_EXIT_IDX1) { /* We didn't start executing this TB (eg because the instruction * counter hit zero); we must restore the guest PC to the address @@ -208,6 +212,7 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles, max_cycles); cpu->current_tb = tb; /* execute the generated code */ + trace_exec_tb_nocache(tb, tb->pc); cpu_tb_exec(cpu, tb->tc_ptr); cpu->current_tb = NULL; tb_phys_invalidate(tb, -1); @@ -749,6 +754,7 @@ int cpu_exec(CPUArchState *env) cpu->current_tb = tb; barrier(); if (likely(!cpu->exit_request)) { + trace_exec_tb(tb, tb->pc); tc_ptr = tb->tc_ptr; /* execute the generated code */ next_tb = cpu_tb_exec(cpu, tc_ptr); diff --git a/trace-events b/trace-events index 11a17a8a40..dcc33dd750 100644 --- a/trace-events +++ b/trace-events @@ -1265,6 +1265,15 @@ kvm_failed_spr_get(int str, const char *msg) "Warning: Unable to retrieve SPR %d kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s" kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s" +# TCG related tracing (mostly disabled by default) +# cpu-exec.c +disable exec_tb(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR +disable exec_tb_nocache(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR +disable exec_tb_exit(void *next_tb, unsigned int flags) "tb:%p flags=%x" + +# translate-all.c +translate_block(void *tb, uintptr_t pc, uint8_t *tb_code) "tb:%p, pc:0x%"PRIxPTR", tb_code:%p" + # memory.c memory_region_ops_read(void *mr, uint64_t addr, uint64_t value, unsigned size) "mr %p addr %#"PRIx64" value %#"PRIx64" size %u" memory_region_ops_write(void *mr, uint64_t addr, uint64_t value, unsigned size) "mr %p addr %#"PRIx64" value %#"PRIx64" size %u" diff --git a/translate-all.c b/translate-all.c index 8f7e11b0a5..2e0265ae27 100644 --- a/translate-all.c +++ b/translate-all.c @@ -33,6 +33,7 @@ #include "qemu-common.h" #define NO_CPU_IO_DEFS #include "cpu.h" +#include "trace.h" #include "disas/disas.h" #include "tcg.h" #if defined(CONFIG_USER_ONLY) @@ -158,6 +159,8 @@ int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_size_ptr gen_intermediate_code(env, tb); + trace_translate_block(tb, tb->pc, tb->tc_ptr); + /* generate machine code */ gen_code_buf = tb->tc_ptr; tb->tb_next_offset[0] = 0xffff; From 4ac4458076e1aaf3b01a6361154117df20e22215 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 4 Aug 2014 16:22:44 +0530 Subject: [PATCH 18/18] virtio-rng: add some trace events Add some trace events to virtio-rng for easier debugging Signed-off-by: Amit Shah Reviewed-by: Amos Kong Signed-off-by: Stefan Hajnoczi --- hw/virtio/virtio-rng.c | 6 ++++++ trace-events | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index 03fd04a1e5..e85a979754 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -16,6 +16,7 @@ #include "hw/virtio/virtio-rng.h" #include "sysemu/rng.h" #include "qom/object_interfaces.h" +#include "trace.h" static bool is_guest_ready(VirtIORNG *vrng) { @@ -24,6 +25,7 @@ static bool is_guest_ready(VirtIORNG *vrng) && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { return true; } + trace_virtio_rng_guest_not_ready(vrng); return false; } @@ -62,6 +64,7 @@ static void chr_read(void *opaque, const void *buf, size_t size) offset += len; virtqueue_push(vrng->vq, &elem, len); + trace_virtio_rng_pushed(vrng, len); } virtio_notify(vdev, vrng->vq); } @@ -81,6 +84,9 @@ static void virtio_rng_process(VirtIORNG *vrng) quota = MIN((uint64_t)vrng->quota_remaining, (uint64_t)UINT32_MAX); } size = get_request_size(vrng->vq, quota); + + trace_virtio_rng_request(vrng, size, quota); + size = MIN(vrng->quota_remaining, size); if (size) { rng_backend_request_entropy(vrng->rng, size, chr_read, vrng); diff --git a/trace-events b/trace-events index dcc33dd750..81bc915edd 100644 --- a/trace-events +++ b/trace-events @@ -41,6 +41,11 @@ virtio_irq(void *vq) "vq %p" virtio_notify(void *vdev, void *vq) "vdev %p vq %p" virtio_set_status(void *vdev, uint8_t val) "vdev %p val %u" +# hw/virtio/virtio-rng.c +virtio_rng_guest_not_ready(void *rng) "rng %p: guest not ready" +virtio_rng_pushed(void *rng, size_t len) "rng %p: %zd bytes pushed" +virtio_rng_request(void *rng, size_t size, unsigned quota) "rng %p: %zd bytes requested, %u bytes quota left" + # hw/char/virtio-serial-bus.c virtio_serial_send_control_event(unsigned int port, uint16_t event, uint16_t value) "port %u, event %u, value %u" virtio_serial_throttle_port(unsigned int port, bool throttle) "port %u, throttle %d"