From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:56699) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SCYDm-0001AO-I7 for qemu-devel@nongnu.org; Tue, 27 Mar 2012 11:22:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SCYDj-00059t-TU for qemu-devel@nongnu.org; Tue, 27 Mar 2012 11:22:06 -0400 Received: from mx1.redhat.com ([209.132.183.28]:1026) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SCYDj-00059K-Iu for qemu-devel@nongnu.org; Tue, 27 Mar 2012 11:22:03 -0400 Date: Tue, 27 Mar 2012 17:21:53 +0200 From: Alon Levy Message-ID: <20120327152153.GM32389@garlic> References: <20120326173743.20814.3629.stgit@ginnungagap.bsc.es> <20120326173750.20814.75373.stgit@ginnungagap.bsc.es> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline In-Reply-To: <20120326173750.20814.75373.stgit@ginnungagap.bsc.es> Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [RFC PATCH v2 1/8] tracetool: Rewrite infrastructure as python modules List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: =?iso-8859-1?Q?Llu=EDs?= Vilanova Cc: stefanha@gmail.com, qemu-devel@nongnu.org On Mon, Mar 26, 2012 at 07:37:50PM +0200, Llu=EDs Vilanova wrote: An additional comment I forgot to add. > Signed-off-by: Llu=EDs Vilanova > --- [snip] > + def __str__(self): > + """String suitable for declaring function arguments.""" > + if len(self._args) =3D=3D 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 =3D re.compile("((?P.*)\s+)?(?P[^(\s]+)\((?P[^)]*)\)\s*(?P\".*)?") > + > + _VALID_PROPS =3D set(["disable"]) > + > + def __init__(self, line): > + m =3D self._CRE.match(line) > + assert m is not None > + groups =3D m.groupdict('') > + self.name =3D groups["name"] > + self.fmt =3D groups["fmt"] > + self.properties =3D groups["props"].split() > + self.args =3D Arguments(groups["args"]) > + > + unknown_props =3D set(self.properties) - self._VALID_PROPS > + if len(unknown_props) > 0: > + raise ValueError("Unknown properties: %s" % ", ".join(unkn= own_props)) > + > + > +def _read_events(fobj): > + res =3D [] > + 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 =3D None, attr_default =3D 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 mod= ule or > + object or attribute value. > + """ > + mod_name =3D mod_name.replace("-", "_") > + try: > + module =3D __import__(mod_name, fromlist=3D["__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 =3D str(format) > + if len(format) is 0: > + raise TracetoolError("format not set") > + mformat =3D format.replace("-", "_") > + if not tracetool.format.exists(mformat): > + raise TracetoolError("unknown format: %s" % format) > + > + backend =3D str(backend) > + if len(backend) is 0: > + raise TracetoolError("backend not set") > + mbackend =3D 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 =3D _read_events(fevents) > + > + if backend =3D=3D "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 lin= e will be > +considered its short description. > + > +All backends must generate their contents through the 'tracetool.out' = routine. > + > + > +Backend attributes > +------------------ > + > +=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > +Attribute Description > +=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > +PUBLIC If exists and is set to 'True', the backend is considered "p= ublic". > +=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > + > + > +Backend functions > +----------------- > + > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > +Function Description > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > + Called to generate the format- and backend-specific code for = each of > + the specified events. If the function does not exist, the bac= kend is > + considered not compatible with the given format. > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > +""" > + > +__author__ =3D "Llu=EDs Vilanova " > +__copyright__ =3D "Copyright 2012, Llu=EDs Vilanova " > +__license__ =3D "GPL version 2 or (at your option) any later versio= n" > + > +__maintainer__ =3D "Stefan Hajnoczi" > +__email__ =3D "stefanha@linux.vnet.ibm.com" > + > + > +import pkgutil > + > +import tracetool > + > + > +def get_list(only_public =3D False): > + """Get a list of (name, description) pairs.""" > + res =3D [("nop", "Tracing disabled.")] > + for _, modname, _ in pkgutil.iter_modules(tracetool.backend.__path= __): > + module =3D tracetool.try_import("tracetool.backend." + modname= )[1] > + > + public =3D getattr(module, "PUBLIC", False) > + if only_public and not public: > + continue > + > + doc =3D module.__doc__ > + if doc is None: > + doc =3D "" > + doc =3D doc.strip().split("\n")[0] > + > + name =3D modname.replace("_", "-") > + res.append((name, doc)) > + return res > + > + > +def exists(name): > + """Return whether the given backend exists.""" > + if len(name) =3D=3D 0: > + return False > + name =3D name.replace("-", "_") > + if name =3D=3D "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 =3D=3D "nop": > + return True > + else: > + func =3D 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) p= air.""" > + if not compatible(backend, format): > + raise ValueError("backend '%s' not compatible with format '%s'= " % > + (backend, format)) > + > + if backend =3D=3D "nop": > + func =3D tracetool.try_import("tracetool.format." + format, > + "nop", _empty)[1] > + else: > + func =3D tracetool.try_import("tracetool.backend." + backend, > + format, None)[1] > + > + func(events) > diff --git a/scripts/tracetool/format/__init__.py b/scripts/tracetool/f= ormat/__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 li= ne will be > +considered its short description. > + > +All formats must generate their contents through the 'tracetool.out' r= outine. > + > + > +Format functions > +---------------- > + > +All the following functions are optional, and no output will be genera= ted if > +they do not exist. > + > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > +Function Description > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > +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 d= isabled or > + the selected backend is 'nop'. > +=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > +""" > + > +__author__ =3D "Llu=EDs Vilanova " > +__copyright__ =3D "Copyright 2012, Llu=EDs Vilanova " > +__license__ =3D "GPL version 2 or (at your option) any later versio= n" > + > +__maintainer__ =3D "Stefan Hajnoczi" > +__email__ =3D "stefanha@linux.vnet.ibm.com" > + > + > +import pkgutil > + > +import tracetool > + > + > +def get_list(): > + """Get a list of (name, description) pairs.""" > + res =3D [] > + for _, modname, _ in pkgutil.iter_modules(tracetool.format.__path_= _): > + module =3D tracetool.try_import("tracetool.format." + modname)= [1] > + > + doc =3D module.__doc__ > + if doc is None: > + doc =3D "" > + doc =3D doc.strip().split("\n")[0] > + > + name =3D modname.replace("_", "-") > + res.append((name, doc)) > + return res > + > + > +def exists(name): > + """Return whether the given format exists.""" > + if len(name) =3D=3D 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 =3D 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 =3D tracetool.try_import("tracetool.format." + name, > + "end", _empty)[1] > + func(events) >=20 >=20