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)
>
>
next prev 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).