diff options
Diffstat (limited to 'scripts/tracetool/backend')
-rw-r--r-- | scripts/tracetool/backend/__init__.py | 125 | ||||
-rw-r--r-- | scripts/tracetool/backend/dtrace.py | 72 | ||||
-rw-r--r-- | scripts/tracetool/backend/ftrace.py | 55 | ||||
-rw-r--r-- | scripts/tracetool/backend/log.py | 64 | ||||
-rw-r--r-- | scripts/tracetool/backend/simple.py | 111 | ||||
-rw-r--r-- | scripts/tracetool/backend/syslog.py | 52 | ||||
-rw-r--r-- | scripts/tracetool/backend/ust.py | 45 |
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) |