All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alon Levy <alevy@redhat.com>
To: "Lluís Vilanova" <vilanova@ac.upc.edu>
Cc: stefanha@gmail.com, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [RFC PATCH v2 1/8] tracetool: Rewrite infrastructure as python modules
Date: Tue, 27 Mar 2012 17:21:53 +0200	[thread overview]
Message-ID: <20120327152153.GM32389@garlic> (raw)
In-Reply-To: <20120326173750.20814.75373.stgit@ginnungagap.bsc.es>

On Mon, Mar 26, 2012 at 07:37:50PM +0200, Lluís Vilanova wrote:

An additional comment I forgot to add.

> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> ---
[snip]
> +    def __str__(self):
> +        """String suitable for declaring function arguments."""
> +        if len(self._args) == 0:
> +            return "void"
> +        else:
> +            return ", ".join([ " ".join([t, n]) for t,n in self._args ])
> +

Nice to have addition (for debugging mainly):

+    def __repr__(self):
+        """String suitable to recreate this instance."""
+        return '%s("%s")' % (self.__class__.__name__, str(self))
+

> +    def names(self):
> +        """List of argument names."""
> +        return [ name for _, name in self._args ]
> +
> +    def types(self):
> +        """List of argument types."""
> +        return [ type_ for type_, _ in self._args ]
> +
> +
> +class Event(object):
> +    """Event description.
> +
> +    Parameters
> +    ----------
> +    line : str
> +        Line describing the event.
> +
> +    Attributes
> +    ----------
> +    name : str
> +        The event name.
> +    fmt : str
> +        The event format string.
> +    properties : set(str)
> +        Properties of the event.
> +    args : Arguments
> +        The event arguments.
> +    """
> +
> +    _CRE = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?")
> +
> +    _VALID_PROPS = set(["disable"])
> +
> +    def __init__(self, line):
> +        m = self._CRE.match(line)
> +        assert m is not None
> +        groups = m.groupdict('')
> +        self.name = groups["name"]
> +        self.fmt = groups["fmt"]
> +        self.properties = groups["props"].split()
> +        self.args = Arguments(groups["args"])
> +
> +        unknown_props = set(self.properties) - self._VALID_PROPS
> +        if len(unknown_props) > 0:
> +            raise ValueError("Unknown properties: %s" % ", ".join(unknown_props))
> +
> +
> +def _read_events(fobj):
> +    res = []
> +    for line in fobj:
> +        if not line.strip():
> +            continue
> +        if line.lstrip().startswith('#'):
> +	    continue
> +        res.append(Event(line))
> +    return res
> +
> +
> +class TracetoolError (Exception):
> +    """Exception for calls to generate."""
> +    pass
> +
> +
> +def try_import(mod_name, attr_name = None, attr_default = None):
> +    """Try to import a module and get an attribute from it.
> +
> +    Parameters
> +    ----------
> +    mod_name : str
> +        Module name.
> +    attr_name : str, optional
> +        Name of an attribute in the module.
> +    attr_default : optional
> +        Default value if the attribute does not exist in the module.
> +
> +    Returns
> +    -------
> +    A pair indicating whether the module could be imported and the module or
> +    object or attribute value.
> +    """
> +    mod_name = mod_name.replace("-", "_")
> +    try:
> +        module = __import__(mod_name, fromlist=["__package__"])
> +        if attr_name is None:
> +            return True, module
> +        return True, getattr(module, str(attr_name), attr_default)
> +    except ImportError:
> +        return False, None
> +
> +
> +def generate(fevents, format, backend, **options):
> +    """Generate the output for the given (format, backend) pair."""
> +    # fix strange python error (UnboundLocalError tracetool)
> +    import tracetool
> +
> +    if len(options) > 0:
> +        raise ValueError("unknown options: " + ", ".join(options))
> +
> +    format = str(format)
> +    if len(format) is 0:
> +        raise TracetoolError("format not set")
> +    mformat = format.replace("-", "_")
> +    if not tracetool.format.exists(mformat):
> +        raise TracetoolError("unknown format: %s" % format)
> +
> +    backend = str(backend)
> +    if len(backend) is 0:
> +        raise TracetoolError("backend not set")
> +    mbackend = backend.replace("-", "_")
> +    if not tracetool.backend.exists(mbackend):
> +        raise TracetoolError("unknown backend: %s" % backend)
> +
> +    if not tracetool.backend.compatible(mbackend, mformat):
> +        raise TracetoolError("backend '%s' not compatible with format '%s'" %
> +                             (backend, format))
> +
> +    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)
> diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py
> new file mode 100644
> index 0000000..23cad9f
> --- /dev/null
> +++ b/scripts/tracetool/backend/__init__.py
> @@ -0,0 +1,114 @@
> +#!/usr/bin/env python
> +# -*- 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
> +-----------------
> +
> +======== =======================================================================
> +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.
> +======== =======================================================================
> +"""
> +
> +__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
> +__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
> +__license__    = "GPL version 2 or (at your option) any later version"
> +
> +__maintainer__ = "Stefan Hajnoczi"
> +__email__      = "stefanha@linux.vnet.ibm.com"
> +
> +
> +import pkgutil
> +
> +import tracetool
> +
> +
> +def get_list(only_public = False):
> +    """Get a list of (name, description) pairs."""
> +    res = [("nop", "Tracing disabled.")]
> +    for _, modname, _ in pkgutil.iter_modules(tracetool.backend.__path__):
> +        module = tracetool.try_import("tracetool.backend." + modname)[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
> +    name = name.replace("-", "_")
> +    if name == "nop":
> +        return True
> +    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)
> +
> +    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
> +
> +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))
> +
> +    if backend == "nop":
> +        func = tracetool.try_import("tracetool.format." + format,
> +                                    "nop", _empty)[1]
> +    else:
> +        func = tracetool.try_import("tracetool.backend." + backend,
> +                                    format, None)[1]
> +
> +    func(events)
> diff --git a/scripts/tracetool/format/__init__.py b/scripts/tracetool/format/__init__.py
> new file mode 100644
> index 0000000..5b37c00
> --- /dev/null
> +++ b/scripts/tracetool/format/__init__.py
> @@ -0,0 +1,91 @@
> +#!/usr/bin/env python
> +# -*- coding: utf-8 -*-
> +
> +"""
> +Format management.
> +
> +
> +Creating new formats
> +--------------------
> +
> +A new format named 'foo-bar' corresponds to Python module
> +'tracetool/frontend/foo_bar.py'.
> +
> +A frontend module should provide a docstring, whose first non-empty line will be
> +considered its short description.
> +
> +All formats must generate their contents through the 'tracetool.out' routine.
> +
> +
> +Format functions
> +----------------
> +
> +All the following functions are optional, and no output will be generated if
> +they do not exist.
> +
> +======== =======================================================================
> +Function Description
> +======== =======================================================================
> +begin    Called to generate the format-specific file header.
> +end      Called to generate the format-specific file footer.
> +nop      Called to generate the per-event contents when the event is disabled or
> +         the selected backend is 'nop'.
> +======== =======================================================================
> +"""
> +
> +__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
> +__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
> +__license__    = "GPL version 2 or (at your option) any later version"
> +
> +__maintainer__ = "Stefan Hajnoczi"
> +__email__      = "stefanha@linux.vnet.ibm.com"
> +
> +
> +import pkgutil
> +
> +import tracetool
> +
> +
> +def get_list():
> +    """Get a list of (name, description) pairs."""
> +    res = []
> +    for _, modname, _ in pkgutil.iter_modules(tracetool.format.__path__):
> +        module = tracetool.try_import("tracetool.format." + modname)[1]
> +
> +        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 format exists."""
> +    if len(name) == 0:
> +        return False
> +    return tracetool.try_import("tracetool.format." + name)[1]
> +
> +
> +def _empty(events):
> +    pass
> +
> +def generate_begin(name, events):
> +    """Generate the header of the format-specific file."""
> +    if not exists(name):
> +        raise ValueError("unknown format: %s" % name)
> +
> +    func = tracetool.try_import("tracetool.format." + name,
> +                                "begin", _empty)[1]
> +    func(events)
> +
> +def generate_end(name, events):
> +    """Generate the footer of the format-specific file."""
> +    if not exists(name):
> +        raise ValueError("unknown format: %s" % name)
> +
> +    func = tracetool.try_import("tracetool.format." + name,
> +                                "end", _empty)[1]
> +    func(events)
> 
> 

  parent reply	other threads:[~2012-03-27 15:22 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-26 17:37 [Qemu-devel] [RFC PATCH v2 0/8] Rewrite tracetool using python modules Lluís Vilanova
2012-03-26 17:37 ` [Qemu-devel] [RFC PATCH v2 1/8] tracetool: Rewrite infrastructure as " Lluís Vilanova
2012-03-27 15:17   ` Alon Levy
2012-03-27 17:47     ` Lluís Vilanova
2012-03-27 15:21   ` Alon Levy [this message]
2012-03-27 16:37   ` [Qemu-devel] [PATCH] tracetool.py: always pass --binary, --target-arch, --target-type Alon Levy
2012-03-27 18:01     ` Lluís Vilanova
2012-03-28  9:35       ` Alon Levy
2012-03-28 10:29         ` Lluís Vilanova
2012-03-26 17:37 ` [Qemu-devel] [RFC PATCH v2 2/8] tracetool: Add module for the 'c' format Lluís Vilanova
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 3/8] tracetool: Add module for the 'h' format Lluís Vilanova
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 4/8] tracetool: Add support for the 'stderr' backend Lluís Vilanova
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 5/8] tracetool: Add support for the 'simple' backend Lluís Vilanova
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 6/8] tracetool: Add support for the 'ust' backend Lluís Vilanova
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 7/8] tracetool: Add support for the 'dtrace' backend Lluís Vilanova
2012-03-27 15:19   ` Alon Levy
2012-03-27 16:20   ` Alon Levy
2012-03-26 17:38 ` [Qemu-devel] [RFC PATCH v2 8/8] tracetool: Add MAINTAINERS info Lluís Vilanova

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120327152153.GM32389@garlic \
    --to=alevy@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@gmail.com \
    --cc=vilanova@ac.upc.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.