aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/tracetool/backend
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/tracetool/backend')
-rw-r--r--scripts/tracetool/backend/__init__.py125
-rw-r--r--scripts/tracetool/backend/dtrace.py72
-rw-r--r--scripts/tracetool/backend/ftrace.py55
-rw-r--r--scripts/tracetool/backend/log.py64
-rw-r--r--scripts/tracetool/backend/simple.py111
-rw-r--r--scripts/tracetool/backend/syslog.py52
-rw-r--r--scripts/tracetool/backend/ust.py45
7 files changed, 524 insertions, 0 deletions
diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py
new file mode 100644
index 000000000..7bfcc86cc
--- /dev/null
+++ b/scripts/tracetool/backend/__init__.py
@@ -0,0 +1,125 @@
+# -*- coding: utf-8 -*-
+
+"""
+Backend management.
+
+
+Creating new backends
+---------------------
+
+A new backend named 'foo-bar' corresponds to Python module
+'tracetool/backend/foo_bar.py'.
+
+A backend module should provide a docstring, whose first non-empty line will be
+considered its short description.
+
+All backends must generate their contents through the 'tracetool.out' routine.
+
+
+Backend attributes
+------------------
+
+========= ====================================================================
+Attribute Description
+========= ====================================================================
+PUBLIC If exists and is set to 'True', the backend is considered "public".
+========= ====================================================================
+
+
+Backend functions
+-----------------
+
+All the following functions are optional, and no output will be generated if
+they do not exist.
+
+=============================== ==============================================
+Function Description
+=============================== ==============================================
+generate_<format>_begin(events) Generate backend- and format-specific file
+ header contents.
+generate_<format>_end(events) Generate backend- and format-specific file
+ footer contents.
+generate_<format>(event) Generate backend- and format-specific contents
+ for the given event.
+=============================== ==============================================
+
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@redhat.com"
+
+
+import os
+
+import tracetool
+
+
+def get_list(only_public = False):
+ """Get a list of (name, description) pairs."""
+ res = [("nop", "Tracing disabled.")]
+ modnames = []
+ for filename in os.listdir(tracetool.backend.__path__[0]):
+ if filename.endswith('.py') and filename != '__init__.py':
+ modnames.append(filename.rsplit('.', 1)[0])
+ for modname in sorted(modnames):
+ module = tracetool.try_import("tracetool.backend." + modname)
+
+ # just in case; should never fail unless non-module files are put there
+ if not module[0]:
+ continue
+ module = module[1]
+
+ public = getattr(module, "PUBLIC", False)
+ if only_public and not public:
+ continue
+
+ doc = module.__doc__
+ if doc is None:
+ doc = ""
+ doc = doc.strip().split("\n")[0]
+
+ name = modname.replace("_", "-")
+ res.append((name, doc))
+ return res
+
+
+def exists(name):
+ """Return whether the given backend exists."""
+ if len(name) == 0:
+ return False
+ if name == "nop":
+ return True
+ name = name.replace("-", "_")
+ return tracetool.try_import("tracetool.backend." + name)[1]
+
+
+class Wrapper:
+ def __init__(self, backends, format):
+ self._backends = [backend.replace("-", "_") for backend in backends]
+ self._format = format.replace("-", "_")
+ for backend in self._backends:
+ assert exists(backend)
+ assert tracetool.format.exists(self._format)
+
+ def _run_function(self, name, *args, **kwargs):
+ for backend in self._backends:
+ func = tracetool.try_import("tracetool.backend." + backend,
+ name % self._format, None)[1]
+ if func is not None:
+ func(*args, **kwargs)
+
+ def generate_begin(self, events, group):
+ self._run_function("generate_%s_begin", events, group)
+
+ def generate(self, event, group):
+ self._run_function("generate_%s", event, group)
+
+ def generate_backend_dstate(self, event, group):
+ self._run_function("generate_%s_backend_dstate", event, group)
+
+ def generate_end(self, events, group):
+ self._run_function("generate_%s_end", events, group)
diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py
new file mode 100644
index 000000000..e17edc9b9
--- /dev/null
+++ b/scripts/tracetool/backend/dtrace.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+
+"""
+DTrace/SystemTAP backend.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2017, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@redhat.com"
+
+
+from tracetool import out
+
+
+PUBLIC = True
+
+
+PROBEPREFIX = None
+
+def probeprefix():
+ if PROBEPREFIX is None:
+ raise ValueError("you must set PROBEPREFIX")
+ return PROBEPREFIX
+
+
+BINARY = None
+
+def binary():
+ if BINARY is None:
+ raise ValueError("you must set BINARY")
+ return BINARY
+
+
+def generate_h_begin(events, group):
+ if group == "root":
+ header = "trace-dtrace-root.h"
+ else:
+ header = "trace-dtrace-%s.h" % group
+
+ # Workaround for ust backend, which also includes <sys/sdt.h> and may
+ # require SDT_USE_VARIADIC to be defined. If dtrace includes <sys/sdt.h>
+ # first without defining SDT_USE_VARIADIC then ust breaks because the
+ # STAP_PROBEV() macro is not defined.
+ out('#ifndef SDT_USE_VARIADIC')
+ out('#define SDT_USE_VARIADIC 1')
+ out('#endif')
+
+ out('#include "%s"' % header,
+ '')
+
+ out('#undef SDT_USE_VARIADIC')
+
+ # SystemTap defines <provider>_<name>_ENABLED() but other DTrace
+ # implementations might not.
+ for e in events:
+ out('#ifndef QEMU_%(uppername)s_ENABLED',
+ '#define QEMU_%(uppername)s_ENABLED() true',
+ '#endif',
+ uppername=e.name.upper())
+
+def generate_h(event, group):
+ out(' QEMU_%(uppername)s(%(argnames)s);',
+ uppername=event.name.upper(),
+ argnames=", ".join(event.args.names()))
+
+
+def generate_h_backend_dstate(event, group):
+ out(' QEMU_%(uppername)s_ENABLED() || \\',
+ uppername=event.name.upper())
diff --git a/scripts/tracetool/backend/ftrace.py b/scripts/tracetool/backend/ftrace.py
new file mode 100644
index 000000000..5fa30ccc0
--- /dev/null
+++ b/scripts/tracetool/backend/ftrace.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+
+"""
+Ftrace built-in backend.
+"""
+
+__author__ = "Eiichi Tsukata <eiichi.tsukata.xh@hitachi.com>"
+__copyright__ = "Copyright (C) 2013 Hitachi, Ltd."
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@redhat.com"
+
+
+from tracetool import out
+
+
+PUBLIC = True
+
+
+def generate_h_begin(events, group):
+ out('#include "trace/ftrace.h"',
+ '')
+
+
+def generate_h(event, group):
+ argnames = ", ".join(event.args.names())
+ if len(event.args) > 0:
+ argnames = ", " + argnames
+
+ out(' {',
+ ' char ftrace_buf[MAX_TRACE_STRLEN];',
+ ' int unused __attribute__ ((unused));',
+ ' int trlen;',
+ ' if (trace_event_get_state(%(event_id)s)) {',
+ '#line %(event_lineno)d "%(event_filename)s"',
+ ' trlen = snprintf(ftrace_buf, MAX_TRACE_STRLEN,',
+ ' "%(name)s " %(fmt)s "\\n" %(argnames)s);',
+ '#line %(out_next_lineno)d "%(out_filename)s"',
+ ' trlen = MIN(trlen, MAX_TRACE_STRLEN - 1);',
+ ' unused = write(trace_marker_fd, ftrace_buf, trlen);',
+ ' }',
+ ' }',
+ name=event.name,
+ args=event.args,
+ event_id="TRACE_" + event.name.upper(),
+ event_lineno=event.lineno,
+ event_filename=event.filename,
+ fmt=event.fmt.rstrip("\n"),
+ argnames=argnames)
+
+
+def generate_h_backend_dstate(event, group):
+ out(' trace_event_get_state_dynamic_by_id(%(event_id)s) || \\',
+ event_id="TRACE_" + event.name.upper())
diff --git a/scripts/tracetool/backend/log.py b/scripts/tracetool/backend/log.py
new file mode 100644
index 000000000..17ba1cd90
--- /dev/null
+++ b/scripts/tracetool/backend/log.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+
+"""
+Stderr built-in backend.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2017, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@redhat.com"
+
+
+from tracetool import out
+
+
+PUBLIC = True
+
+
+def generate_h_begin(events, group):
+ out('#include "qemu/log-for-trace.h"',
+ '#include "qemu/error-report.h"',
+ '')
+
+
+def generate_h(event, group):
+ argnames = ", ".join(event.args.names())
+ if len(event.args) > 0:
+ argnames = ", " + argnames
+
+ if "vcpu" in event.properties:
+ # already checked on the generic format code
+ cond = "true"
+ else:
+ cond = "trace_event_get_state(%s)" % ("TRACE_" + event.name.upper())
+
+ out(' if (%(cond)s && qemu_loglevel_mask(LOG_TRACE)) {',
+ ' if (message_with_timestamp) {',
+ ' struct timeval _now;',
+ ' gettimeofday(&_now, NULL);',
+ '#line %(event_lineno)d "%(event_filename)s"',
+ ' qemu_log("%%d@%%zu.%%06zu:%(name)s " %(fmt)s "\\n",',
+ ' qemu_get_thread_id(),',
+ ' (size_t)_now.tv_sec, (size_t)_now.tv_usec',
+ ' %(argnames)s);',
+ '#line %(out_next_lineno)d "%(out_filename)s"',
+ ' } else {',
+ '#line %(event_lineno)d "%(event_filename)s"',
+ ' qemu_log("%(name)s " %(fmt)s "\\n"%(argnames)s);',
+ '#line %(out_next_lineno)d "%(out_filename)s"',
+ ' }',
+ ' }',
+ cond=cond,
+ event_lineno=event.lineno,
+ event_filename=event.filename,
+ name=event.name,
+ fmt=event.fmt.rstrip("\n"),
+ argnames=argnames)
+
+
+def generate_h_backend_dstate(event, group):
+ out(' trace_event_get_state_dynamic_by_id(%(event_id)s) || \\',
+ event_id="TRACE_" + event.name.upper())
diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py
new file mode 100644
index 000000000..a74d61fcd
--- /dev/null
+++ b/scripts/tracetool/backend/simple.py
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+
+"""
+Simple built-in backend.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2017, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@redhat.com"
+
+
+from tracetool import out
+
+
+PUBLIC = True
+
+
+def is_string(arg):
+ strtype = ('const char*', 'char*', 'const char *', 'char *')
+ arg_strip = arg.lstrip()
+ if arg_strip.startswith(strtype) and arg_strip.count('*') == 1:
+ return True
+ else:
+ return False
+
+
+def generate_h_begin(events, group):
+ for event in events:
+ out('void _simple_%(api)s(%(args)s);',
+ api=event.api(),
+ args=event.args)
+ out('')
+
+
+def generate_h(event, group):
+ out(' _simple_%(api)s(%(args)s);',
+ api=event.api(),
+ args=", ".join(event.args.names()))
+
+
+def generate_h_backend_dstate(event, group):
+ out(' trace_event_get_state_dynamic_by_id(%(event_id)s) || \\',
+ event_id="TRACE_" + event.name.upper())
+
+
+def generate_c_begin(events, group):
+ out('#include "qemu/osdep.h"',
+ '#include "trace/control.h"',
+ '#include "trace/simple.h"',
+ '')
+
+
+def generate_c(event, group):
+ out('void _simple_%(api)s(%(args)s)',
+ '{',
+ ' TraceBufferRecord rec;',
+ api=event.api(),
+ args=event.args)
+ sizes = []
+ for type_, name in event.args:
+ if is_string(type_):
+ out(' size_t arg%(name)s_len = %(name)s ? MIN(strlen(%(name)s), MAX_TRACE_STRLEN) : 0;',
+ name=name)
+ strsizeinfo = "4 + arg%s_len" % name
+ sizes.append(strsizeinfo)
+ else:
+ sizes.append("8")
+ sizestr = " + ".join(sizes)
+ if len(event.args) == 0:
+ sizestr = '0'
+
+ event_id = 'TRACE_' + event.name.upper()
+ if "vcpu" in event.properties:
+ # already checked on the generic format code
+ cond = "true"
+ else:
+ cond = "trace_event_get_state(%s)" % event_id
+
+ out('',
+ ' if (!%(cond)s) {',
+ ' return;',
+ ' }',
+ '',
+ ' if (trace_record_start(&rec, %(event_obj)s.id, %(size_str)s)) {',
+ ' return; /* Trace Buffer Full, Event Dropped ! */',
+ ' }',
+ cond=cond,
+ event_obj=event.api(event.QEMU_EVENT),
+ size_str=sizestr)
+
+ if len(event.args) > 0:
+ for type_, name in event.args:
+ # string
+ if is_string(type_):
+ out(' trace_record_write_str(&rec, %(name)s, arg%(name)s_len);',
+ name=name)
+ # pointer var (not string)
+ elif type_.endswith('*'):
+ out(' trace_record_write_u64(&rec, (uintptr_t)(uint64_t *)%(name)s);',
+ name=name)
+ # primitive data type
+ else:
+ out(' trace_record_write_u64(&rec, (uint64_t)%(name)s);',
+ name=name)
+
+ out(' trace_record_finish(&rec);',
+ '}',
+ '')
diff --git a/scripts/tracetool/backend/syslog.py b/scripts/tracetool/backend/syslog.py
new file mode 100644
index 000000000..5a3a00fe3
--- /dev/null
+++ b/scripts/tracetool/backend/syslog.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+
+"""
+Syslog built-in backend.
+"""
+
+__author__ = "Paul Durrant <paul.durrant@citrix.com>"
+__copyright__ = "Copyright 2016, Citrix Systems Inc."
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@redhat.com"
+
+
+from tracetool import out
+
+
+PUBLIC = True
+
+
+def generate_h_begin(events, group):
+ out('#include <syslog.h>',
+ '')
+
+
+def generate_h(event, group):
+ argnames = ", ".join(event.args.names())
+ if len(event.args) > 0:
+ argnames = ", " + argnames
+
+ if "vcpu" in event.properties:
+ # already checked on the generic format code
+ cond = "true"
+ else:
+ cond = "trace_event_get_state(%s)" % ("TRACE_" + event.name.upper())
+
+ out(' if (%(cond)s) {',
+ '#line %(event_lineno)d "%(event_filename)s"',
+ ' syslog(LOG_INFO, "%(name)s " %(fmt)s %(argnames)s);',
+ '#line %(out_next_lineno)d "%(out_filename)s"',
+ ' }',
+ cond=cond,
+ event_lineno=event.lineno,
+ event_filename=event.filename,
+ name=event.name,
+ fmt=event.fmt.rstrip("\n"),
+ argnames=argnames)
+
+
+def generate_h_backend_dstate(event, group):
+ out(' trace_event_get_state_dynamic_by_id(%(event_id)s) || \\',
+ event_id="TRACE_" + event.name.upper())
diff --git a/scripts/tracetool/backend/ust.py b/scripts/tracetool/backend/ust.py
new file mode 100644
index 000000000..c857516f2
--- /dev/null
+++ b/scripts/tracetool/backend/ust.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+
+"""
+LTTng User Space Tracing backend.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2017, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@redhat.com"
+
+
+from tracetool import out
+
+
+PUBLIC = True
+
+
+def generate_h_begin(events, group):
+ header = 'trace-ust-' + group + '.h'
+ out('#include <lttng/tracepoint.h>',
+ '#include "%s"' % header,
+ '',
+ '/* tracepoint_enabled() was introduced in LTTng UST 2.7 */',
+ '#ifndef tracepoint_enabled',
+ '#define tracepoint_enabled(a, b) true',
+ '#endif',
+ '')
+
+
+def generate_h(event, group):
+ argnames = ", ".join(event.args.names())
+ if len(event.args) > 0:
+ argnames = ", " + argnames
+
+ out(' tracepoint(qemu, %(name)s%(tp_args)s);',
+ name=event.name,
+ tp_args=argnames)
+
+
+def generate_h_backend_dstate(event, group):
+ out(' tracepoint_enabled(qemu, %(name)s) || \\',
+ name=event.name)