Commit 43cbeffb authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/stefanha/tags/tracing-pull-request' into staging



Tracing pull request

# gpg: Signature made Wed 07 May 2014 18:14:02 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"

* remotes/stefanha/tags/tracing-pull-request:
  configure: Show trace output file conditionally
  trace: [tracetool] Minimize the amount of per-backend code
  trace: [simple] Bump up log version number
  trace: [tracetool] Change format docs to point to the generated file
  trace: [tracetool] Show list of frontends and backends sorted by name
  trace: [tracetool] Cosmetic changes
  trace: [tracetool] Spacing changes
  trace: [tracetool] Add methods 'Event.copy' and 'Arguments.copy'
  trace: [tracetool] Add method 'Event.api' to build event names

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 6b342cc9 e00e36fb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -4153,7 +4153,9 @@ echo "libcap-ng support $cap_ng"
echo "vhost-net support $vhost_net"
echo "vhost-scsi support $vhost_scsi"
echo "Trace backend     $trace_backend"
if test "$trace_backend" = "simple"; then
echo "Trace output file $trace_file-<pid>"
fi
if test "$spice" = "yes"; then
echo "spice support     $spice ($spice_protocol_version/$spice_server_version)"
else
+6 −10
Original line number Diff line number Diff line
@@ -65,13 +65,13 @@ def read_trace_file(edict, fobj):
       header[0] != header_event_id or \
       header[1] != header_magic:
        raise ValueError('Not a valid trace file!')
    if header[2] != 0 and \
       header[2] != 2:
        raise ValueError('Unknown version of tracelog format!')

    log_version = header[2]
    if log_version == 0:
        raise ValueError('Older log format, not supported with this QEMU release!')
    if log_version not in [0, 2, 3]:
        raise ValueError('Unknown version of tracelog format!')
    if log_version != 3:
        raise ValueError('Log format %d not supported with this QEMU release!'
                         % log_version)

    while True:
        rec = read_record(edict, fobj)
@@ -109,14 +109,10 @@ def process(events, log, analyzer):
    if isinstance(log, str):
        log = open(log, 'rb')

    enabled_events = []
    dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)")
    edict = {dropped_event_id: dropped_event}

    for e in events:
        if 'disable' not in e.properties:
            enabled_events.append(e)
    for num, event in enumerate(enabled_events):
    for num, event in enumerate(events):
        edict[num] = event

    def build_fn(analyzer, event):
+28 −25
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ Machinery for generating tracing-related intermediate files.
"""

__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
__copyright__  = "Copyright 2012, 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"
@@ -52,6 +52,10 @@ class Arguments:
        """
        self._args = args

    def copy(self):
        """Create a new copy."""
        return Arguments(list(self._args))

    @staticmethod
    def build(arg_str):
        """Build and Arguments instance from an argument string.
@@ -144,7 +148,13 @@ class Event(object):

        unknown_props = set(self.properties) - self._VALID_PROPS
        if len(unknown_props) > 0:
            raise ValueError("Unknown properties: %s" % ", ".join(unknown_props))
            raise ValueError("Unknown properties: %s"
                             % ", ".join(unknown_props))

    def copy(self):
        """Create a new copy."""
        return Event(self.name, list(self.properties), self.fmt,
                     self.args.copy(), self)

    @staticmethod
    def build(line_str):
@@ -173,6 +183,14 @@ class Event(object):
                                          self.args,
                                          self.fmt)

    QEMU_TRACE               = "trace_%(name)s"

    def api(self, fmt=None):
        if fmt is None:
            fmt = Event.QEMU_TRACE
        return fmt % {"name": self.name}


def _read_events(fobj):
    res = []
    for line in fobj:
@@ -238,20 +256,17 @@ def generate(fevents, format, backend,
    format = str(format)
    if len(format) is 0:
        raise TracetoolError("format not set")
    mformat = format.replace("-", "_")
    if not tracetool.format.exists(mformat):
    if not tracetool.format.exists(format):
        raise TracetoolError("unknown format: %s" % format)
    format = format.replace("-", "_")

    backend = str(backend)
    if len(backend) is 0:
        raise TracetoolError("backend not set")
    mbackend = backend.replace("-", "_")
    if not tracetool.backend.exists(mbackend):
    if not tracetool.backend.exists(backend):
        raise TracetoolError("unknown backend: %s" % backend)

    if not tracetool.backend.compatible(mbackend, mformat):
        raise TracetoolError("backend '%s' not compatible with format '%s'" %
                             (backend, format))
    backend = backend.replace("-", "_")
    backend = tracetool.backend.Wrapper(backend, format)

    import tracetool.backend.dtrace
    tracetool.backend.dtrace.BINARY = binary
@@ -259,16 +274,4 @@ def generate(fevents, format, backend,

    events = _read_events(fevents)

    if backend == "nop":
        ( e.properies.add("disable") for e in events )

    tracetool.format.generate_begin(mformat, events)
    tracetool.backend.generate("nop", format,
                               [ e
                                 for e in events
                                 if "disable" in e.properties ])
    tracetool.backend.generate(backend, format,
                               [ e
                                 for e in events
                                 if "disable" not in e.properties ])
    tracetool.format.generate_end(mformat, events)
    tracetool.format.generate(events, format, backend)
+33 −41
Original line number Diff line number Diff line
@@ -30,17 +30,24 @@ 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
======== =======================================================================
<format> Called to generate the format- and backend-specific code for each of
         the specified events. If the function does not exist, the backend is
         considered not compatible with the given format.
======== =======================================================================
=============================== ==============================================
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, 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"
@@ -59,7 +66,7 @@ def get_list(only_public = False):
    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 modnames:
    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
@@ -91,39 +98,24 @@ def exists(name):
    return tracetool.try_import("tracetool.backend." + name)[1]


def compatible(backend, format):
    """Whether a backend is compatible with the given format."""
    if not exists(backend):
        raise ValueError("unknown backend: %s" % backend)

    backend = backend.replace("-", "_")
    format = format.replace("-", "_")

    if backend == "nop":
        return True
    else:
        func = tracetool.try_import("tracetool.backend." + backend,
                                    format, None)[1]
        return func is not None


def _empty(events):
    pass
class Wrapper:
    def __init__(self, backend, format):
        self._backend = backend.replace("-", "_")
        self._format = format.replace("-", "_")
        assert exists(self._backend)
        assert tracetool.format.exists(self._format)

def generate(backend, format, events):
    """Generate the per-event output for the given (backend, format) pair."""
    if not compatible(backend, format):
        raise ValueError("backend '%s' not compatible with format '%s'" %
                         (backend, format))
    def _run_function(self, name, *args, **kwargs):
        func = tracetool.try_import("tracetool.backend." + self._backend,
                                    name % self._format, None)[1]
        if func is not None:
            func(*args, **kwargs)

    backend = backend.replace("-", "_")
    format = format.replace("-", "_")
    def generate_begin(self, events):
        self._run_function("generate_%s_begin", events)

    if backend == "nop":
        func = tracetool.try_import("tracetool.format." + format,
                                    "nop", _empty)[1]
    else:
        func = tracetool.try_import("tracetool.backend." + backend,
                                    format, None)[1]
    def generate(self, event):
        self._run_function("generate_%s", event)

    func(events)
    def generate_end(self, events):
        self._run_function("generate_%s_end", events)
+9 −72
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ DTrace/SystemTAP backend.
"""

__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
__copyright__  = "Copyright 2012, 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"
@@ -21,7 +21,7 @@ PUBLIC = True

PROBEPREFIX = None

def _probeprefix():
def probeprefix():
    if PROBEPREFIX is None:
        raise ValueError("you must set PROBEPREFIX")
    return PROBEPREFIX
@@ -29,81 +29,18 @@ def _probeprefix():

BINARY = None

def _binary():
def binary():
    if BINARY is None:
        raise ValueError("you must set BINARY")
    return BINARY


def c(events):
    pass


def h(events):
def generate_h_begin(events):
    out('#include "trace/generated-tracers-dtrace.h"',
        '')

    for e in events:
        out('static inline void trace_%(name)s(%(args)s) {',
            '    QEMU_%(uppername)s(%(argnames)s);',
            '}',
            name = e.name,
            args = e.args,
            uppername = e.name.upper(),
            argnames = ", ".join(e.args.names()),
            )


def d(events):
    out('provider qemu {')

    for e in events:
        args = str(e.args)

        # DTrace provider syntax expects foo() for empty
        # params, not foo(void)
        if args == 'void':
            args = ''

        # Define prototype for probe arguments
        out('',
            'probe %(name)s(%(args)s);',
            name = e.name,
            args = args,
            )

    out('',
        '};')


# Technically 'self' is not used by systemtap yet, but
# they recommended we keep it in the reserved list anyway
RESERVED_WORDS = (
    'break', 'catch', 'continue', 'delete', 'else', 'for',
    'foreach', 'function', 'global', 'if', 'in', 'limit',
    'long', 'next', 'probe', 'return', 'self', 'string',
    'try', 'while'
    )

def stap(events):
    for e in events:
        # Define prototype for probe arguments
        out('probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")',
            '{',
            probeprefix = _probeprefix(),
            name = e.name,
            binary = _binary(),
            )

        i = 1
        if len(e.args) > 0:
            for name in e.args.names():
                # Append underscore to reserved keywords
                if name in RESERVED_WORDS:
                    name += '_'
                out('  %s = $arg%d;' % (name, i))
                i += 1

        out('}')

    out()

def generate_h(event):
    out('    QEMU_%(uppername)s(%(argnames)s);',
        uppername=event.name.upper(),
        argnames=", ".join(event.args.names()))
Loading