xref: /openbmc/qemu/scripts/tracetool/__init__.py (revision f3e8cc47de2bc537d4991e883a85208e4e1c0f98)
1650ab98dSLluís Vilanova# -*- coding: utf-8 -*-
2650ab98dSLluís Vilanova
3650ab98dSLluís Vilanova"""
4650ab98dSLluís VilanovaMachinery for generating tracing-related intermediate files.
5650ab98dSLluís Vilanova"""
6650ab98dSLluís Vilanova
7650ab98dSLluís Vilanova__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
8864a2178SLluís Vilanova__copyright__  = "Copyright 2012-2017, Lluís Vilanova <vilanova@ac.upc.edu>"
9650ab98dSLluís Vilanova__license__    = "GPL version 2 or (at your option) any later version"
10650ab98dSLluís Vilanova
11650ab98dSLluís Vilanova__maintainer__ = "Stefan Hajnoczi"
12f892b494SPhilippe Mathieu-Daudé__email__      = "stefanha@redhat.com"
13650ab98dSLluís Vilanova
14650ab98dSLluís Vilanova
15650ab98dSLluís Vilanovaimport re
16650ab98dSLluís Vilanovaimport sys
17b55835acSLluís Vilanovaimport weakref
18650ab98dSLluís Vilanova
19650ab98dSLluís Vilanovaimport tracetool.format
20650ab98dSLluís Vilanovaimport tracetool.backend
21650ab98dSLluís Vilanova
22650ab98dSLluís Vilanova
23650ab98dSLluís Vilanovadef error_write(*lines):
24650ab98dSLluís Vilanova    """Write a set of error lines."""
25650ab98dSLluís Vilanova    sys.stderr.writelines("\n".join(lines) + "\n")
26650ab98dSLluís Vilanova
27650ab98dSLluís Vilanovadef error(*lines):
28650ab98dSLluís Vilanova    """Write a set of error lines and exit."""
29650ab98dSLluís Vilanova    error_write(*lines)
30650ab98dSLluís Vilanova    sys.exit(1)
31650ab98dSLluís Vilanova
32650ab98dSLluís Vilanova
33294170c1SStefan Hajnocziout_lineno = 1
34c05012a3SStefan Hajnocziout_filename = '<none>'
35c05012a3SStefan Hajnocziout_fobj = sys.stdout
36c05012a3SStefan Hajnoczi
37c05012a3SStefan Hajnoczidef out_open(filename):
38c05012a3SStefan Hajnoczi    global out_filename, out_fobj
39c05012a3SStefan Hajnoczi    out_filename = filename
40c05012a3SStefan Hajnoczi    out_fobj = open(filename, 'wt')
41c05012a3SStefan Hajnoczi
42650ab98dSLluís Vilanovadef out(*lines, **kwargs):
43650ab98dSLluís Vilanova    """Write a set of output lines.
44650ab98dSLluís Vilanova
4565fdb3ccSzhaolichang    You can use kwargs as a shorthand for mapping variables when formatting all
46650ab98dSLluís Vilanova    the strings in lines.
47c05012a3SStefan Hajnoczi
48294170c1SStefan Hajnoczi    The 'out_lineno' kwarg is automatically added to reflect the current output
49294170c1SStefan Hajnoczi    file line number. The 'out_next_lineno' kwarg is also automatically added
50294170c1SStefan Hajnoczi    with the next output line number. The 'out_filename' kwarg is automatically
51294170c1SStefan Hajnoczi    added with the output filename.
52650ab98dSLluís Vilanova    """
53294170c1SStefan Hajnoczi    global out_lineno
54c05012a3SStefan Hajnoczi    output = []
55c05012a3SStefan Hajnoczi    for l in lines:
56294170c1SStefan Hajnoczi        kwargs['out_lineno'] = out_lineno
57294170c1SStefan Hajnoczi        kwargs['out_next_lineno'] = out_lineno + 1
58c05012a3SStefan Hajnoczi        kwargs['out_filename'] = out_filename
59c05012a3SStefan Hajnoczi        output.append(l % kwargs)
60294170c1SStefan Hajnoczi        out_lineno += 1
61c05012a3SStefan Hajnoczi
62c05012a3SStefan Hajnoczi    out_fobj.writelines("\n".join(output) + "\n")
63650ab98dSLluís Vilanova
6473ff0610SDaniel P. Berrangé# We only want to allow standard C types or fixed sized
6573ff0610SDaniel P. Berrangé# integer types. We don't want QEMU specific types
6673ff0610SDaniel P. Berrangé# as we can't assume trace backends can resolve all the
6773ff0610SDaniel P. Berrangé# typedefs
6873ff0610SDaniel P. BerrangéALLOWED_TYPES = [
6973ff0610SDaniel P. Berrangé    "int",
7073ff0610SDaniel P. Berrangé    "long",
7173ff0610SDaniel P. Berrangé    "short",
7273ff0610SDaniel P. Berrangé    "char",
7373ff0610SDaniel P. Berrangé    "bool",
7473ff0610SDaniel P. Berrangé    "unsigned",
7573ff0610SDaniel P. Berrangé    "signed",
7673ff0610SDaniel P. Berrangé    "int8_t",
7773ff0610SDaniel P. Berrangé    "uint8_t",
7873ff0610SDaniel P. Berrangé    "int16_t",
7973ff0610SDaniel P. Berrangé    "uint16_t",
8073ff0610SDaniel P. Berrangé    "int32_t",
8173ff0610SDaniel P. Berrangé    "uint32_t",
8273ff0610SDaniel P. Berrangé    "int64_t",
8373ff0610SDaniel P. Berrangé    "uint64_t",
8473ff0610SDaniel P. Berrangé    "void",
8573ff0610SDaniel P. Berrangé    "size_t",
8673ff0610SDaniel P. Berrangé    "ssize_t",
8773ff0610SDaniel P. Berrangé    "uintptr_t",
8873ff0610SDaniel P. Berrangé    "ptrdiff_t",
8973ff0610SDaniel P. Berrangé]
9073ff0610SDaniel P. Berrangé
9173ff0610SDaniel P. Berrangédef validate_type(name):
9273ff0610SDaniel P. Berrangé    bits = name.split(" ")
9373ff0610SDaniel P. Berrangé    for bit in bits:
944d96307cSMarc-André Lureau        bit = re.sub(r"\*", "", bit)
9573ff0610SDaniel P. Berrangé        if bit == "":
9673ff0610SDaniel P. Berrangé            continue
9773ff0610SDaniel P. Berrangé        if bit == "const":
9873ff0610SDaniel P. Berrangé            continue
9973ff0610SDaniel P. Berrangé        if bit not in ALLOWED_TYPES:
10054fa79b7SPhilippe Mathieu-Daudé            raise ValueError("Argument type '%s' is not allowed. "
10173ff0610SDaniel P. Berrangé                             "Only standard C types and fixed size integer "
10273ff0610SDaniel P. Berrangé                             "types should be used. struct, union, and "
10373ff0610SDaniel P. Berrangé                             "other complex pointer types should be "
10473ff0610SDaniel P. Berrangé                             "declared as 'void *'" % name)
105650ab98dSLluís Vilanova
106650ab98dSLluís Vilanovaclass Arguments:
107650ab98dSLluís Vilanova    """Event arguments description."""
108650ab98dSLluís Vilanova
109650ab98dSLluís Vilanova    def __init__(self, args):
110650ab98dSLluís Vilanova        """
111650ab98dSLluís Vilanova        Parameters
112650ab98dSLluís Vilanova        ----------
113650ab98dSLluís Vilanova        args :
1143596f524SLluís Vilanova            List of (type, name) tuples or Arguments objects.
115650ab98dSLluís Vilanova        """
1163596f524SLluís Vilanova        self._args = []
1173596f524SLluís Vilanova        for arg in args:
1183596f524SLluís Vilanova            if isinstance(arg, Arguments):
1193596f524SLluís Vilanova                self._args.extend(arg._args)
1203596f524SLluís Vilanova            else:
1213596f524SLluís Vilanova                self._args.append(arg)
122650ab98dSLluís Vilanova
123ad7443e4SLluís Vilanova    def copy(self):
124ad7443e4SLluís Vilanova        """Create a new copy."""
125ad7443e4SLluís Vilanova        return Arguments(list(self._args))
126ad7443e4SLluís Vilanova
127650ab98dSLluís Vilanova    @staticmethod
128650ab98dSLluís Vilanova    def build(arg_str):
129650ab98dSLluís Vilanova        """Build and Arguments instance from an argument string.
130650ab98dSLluís Vilanova
131650ab98dSLluís Vilanova        Parameters
132650ab98dSLluís Vilanova        ----------
133650ab98dSLluís Vilanova        arg_str : str
134650ab98dSLluís Vilanova            String describing the event arguments.
135650ab98dSLluís Vilanova        """
136650ab98dSLluís Vilanova        res = []
137650ab98dSLluís Vilanova        for arg in arg_str.split(","):
138650ab98dSLluís Vilanova            arg = arg.strip()
13924f4d3d3SStefan Hajnoczi            if not arg:
14024f4d3d3SStefan Hajnoczi                raise ValueError("Empty argument (did you forget to use 'void'?)")
141b3ef0adeSStefan Hajnoczi            if arg == 'void':
142650ab98dSLluís Vilanova                continue
143b3ef0adeSStefan Hajnoczi
144b3ef0adeSStefan Hajnoczi            if '*' in arg:
145b3ef0adeSStefan Hajnoczi                arg_type, identifier = arg.rsplit('*', 1)
146b3ef0adeSStefan Hajnoczi                arg_type += '*'
147b3ef0adeSStefan Hajnoczi                identifier = identifier.strip()
148b3ef0adeSStefan Hajnoczi            else:
149b3ef0adeSStefan Hajnoczi                arg_type, identifier = arg.rsplit(None, 1)
150b3ef0adeSStefan Hajnoczi
15173ff0610SDaniel P. Berrangé            validate_type(arg_type)
152b3ef0adeSStefan Hajnoczi            res.append((arg_type, identifier))
153650ab98dSLluís Vilanova        return Arguments(res)
154650ab98dSLluís Vilanova
1553596f524SLluís Vilanova    def __getitem__(self, index):
1563596f524SLluís Vilanova        if isinstance(index, slice):
1573596f524SLluís Vilanova            return Arguments(self._args[index])
1583596f524SLluís Vilanova        else:
1593596f524SLluís Vilanova            return self._args[index]
1603596f524SLluís Vilanova
161650ab98dSLluís Vilanova    def __iter__(self):
162650ab98dSLluís Vilanova        """Iterate over the (type, name) pairs."""
163650ab98dSLluís Vilanova        return iter(self._args)
164650ab98dSLluís Vilanova
165650ab98dSLluís Vilanova    def __len__(self):
166650ab98dSLluís Vilanova        """Number of arguments."""
167650ab98dSLluís Vilanova        return len(self._args)
168650ab98dSLluís Vilanova
169650ab98dSLluís Vilanova    def __str__(self):
170650ab98dSLluís Vilanova        """String suitable for declaring function arguments."""
171650ab98dSLluís Vilanova        if len(self._args) == 0:
172650ab98dSLluís Vilanova            return "void"
173650ab98dSLluís Vilanova        else:
174650ab98dSLluís Vilanova            return ", ".join([ " ".join([t, n]) for t,n in self._args ])
175650ab98dSLluís Vilanova
176650ab98dSLluís Vilanova    def __repr__(self):
177650ab98dSLluís Vilanova        """Evaluable string representation for this object."""
178650ab98dSLluís Vilanova        return "Arguments(\"%s\")" % str(self)
179650ab98dSLluís Vilanova
180650ab98dSLluís Vilanova    def names(self):
181650ab98dSLluís Vilanova        """List of argument names."""
182650ab98dSLluís Vilanova        return [ name for _, name in self._args ]
183650ab98dSLluís Vilanova
184650ab98dSLluís Vilanova    def types(self):
185650ab98dSLluís Vilanova        """List of argument types."""
186650ab98dSLluís Vilanova        return [ type_ for type_, _ in self._args ]
187650ab98dSLluís Vilanova
188bc9beb47SLluís Vilanova    def casted(self):
189bc9beb47SLluís Vilanova        """List of argument names casted to their type."""
190bc9beb47SLluís Vilanova        return ["(%s)%s" % (type_, name) for type_, name in self._args]
191bc9beb47SLluís Vilanova
192650ab98dSLluís Vilanova
193650ab98dSLluís Vilanovaclass Event(object):
194650ab98dSLluís Vilanova    """Event description.
195650ab98dSLluís Vilanova
196650ab98dSLluís Vilanova    Attributes
197650ab98dSLluís Vilanova    ----------
198650ab98dSLluís Vilanova    name : str
199650ab98dSLluís Vilanova        The event name.
200650ab98dSLluís Vilanova    fmt : str
201650ab98dSLluís Vilanova        The event format string.
202650ab98dSLluís Vilanova    properties : set(str)
203650ab98dSLluís Vilanova        Properties of the event.
204650ab98dSLluís Vilanova    args : Arguments
205650ab98dSLluís Vilanova        The event arguments.
2064e66c9efSStefan Hajnoczi    lineno : int
2074e66c9efSStefan Hajnoczi        The line number in the input file.
2084e66c9efSStefan Hajnoczi    filename : str
2094e66c9efSStefan Hajnoczi        The path to the input file.
21023214429SLluís Vilanova
211650ab98dSLluís Vilanova    """
212650ab98dSLluís Vilanova
213e6d8e5e6SPaolo Bonzini    _CRE = re.compile(r"((?P<props>[\w\s]+)\s+)?"
214e6d8e5e6SPaolo Bonzini                      r"(?P<name>\w+)"
215e6d8e5e6SPaolo Bonzini                      r"\((?P<args>[^)]*)\)"
216e6d8e5e6SPaolo Bonzini                      r"\s*"
217e6d8e5e6SPaolo Bonzini                      r"(?:(?:(?P<fmt_trans>\".+),)?\s*(?P<fmt>\".+))?"
218e6d8e5e6SPaolo Bonzini                      r"\s*")
219650ab98dSLluís Vilanova
220126d4123SAlex Bennée    _VALID_PROPS = set(["disable", "vcpu"])
221650ab98dSLluís Vilanova
2224e66c9efSStefan Hajnoczi    def __init__(self, name, props, fmt, args, lineno, filename, orig=None,
2234ade0541SLluís Vilanova                 event_trans=None, event_exec=None):
224650ab98dSLluís Vilanova        """
225650ab98dSLluís Vilanova        Parameters
226650ab98dSLluís Vilanova        ----------
227650ab98dSLluís Vilanova        name : string
228650ab98dSLluís Vilanova            Event name.
229650ab98dSLluís Vilanova        props : list of str
230650ab98dSLluís Vilanova            Property names.
231b2b36c22SLluís Vilanova        fmt : str, list of str
2326e497fa1SStefan Hajnoczi            Event printing format string(s).
233650ab98dSLluís Vilanova        args : Arguments
234650ab98dSLluís Vilanova            Event arguments.
2354e66c9efSStefan Hajnoczi        lineno : int
2364e66c9efSStefan Hajnoczi            The line number in the input file.
2374e66c9efSStefan Hajnoczi        filename : str
2384e66c9efSStefan Hajnoczi            The path to the input file.
239b55835acSLluís Vilanova        orig : Event or None
2404ade0541SLluís Vilanova            Original Event before transformation/generation.
2414ade0541SLluís Vilanova        event_trans : Event or None
2424ade0541SLluís Vilanova            Generated translation-time event ("tcg" property).
2434ade0541SLluís Vilanova        event_exec : Event or None
2444ade0541SLluís Vilanova            Generated execution-time event ("tcg" property).
24541ef7b00SAlex Bennée
246650ab98dSLluís Vilanova        """
247650ab98dSLluís Vilanova        self.name = name
248650ab98dSLluís Vilanova        self.properties = props
249650ab98dSLluís Vilanova        self.fmt = fmt
250650ab98dSLluís Vilanova        self.args = args
2514e66c9efSStefan Hajnoczi        self.lineno = int(lineno)
2524e66c9efSStefan Hajnoczi        self.filename = str(filename)
2534ade0541SLluís Vilanova        self.event_trans = event_trans
2544ade0541SLluís Vilanova        self.event_exec = event_exec
255650ab98dSLluís Vilanova
256f3fddaf6SDaniel P. Berrange        if len(args) > 10:
257f3fddaf6SDaniel P. Berrange            raise ValueError("Event '%s' has more than maximum permitted "
258f3fddaf6SDaniel P. Berrange                             "argument count" % name)
259f3fddaf6SDaniel P. Berrange
260b55835acSLluís Vilanova        if orig is None:
261b55835acSLluís Vilanova            self.original = weakref.ref(self)
262b55835acSLluís Vilanova        else:
263b55835acSLluís Vilanova            self.original = orig
264b55835acSLluís Vilanova
265650ab98dSLluís Vilanova        unknown_props = set(self.properties) - self._VALID_PROPS
266650ab98dSLluís Vilanova        if len(unknown_props) > 0:
2679c24a52eSLluís Vilanova            raise ValueError("Unknown properties: %s"
2689c24a52eSLluís Vilanova                             % ", ".join(unknown_props))
269b2b36c22SLluís Vilanova        assert isinstance(self.fmt, str) or len(self.fmt) == 2
270650ab98dSLluís Vilanova
271ad7443e4SLluís Vilanova    def copy(self):
272ad7443e4SLluís Vilanova        """Create a new copy."""
273ad7443e4SLluís Vilanova        return Event(self.name, list(self.properties), self.fmt,
2744e66c9efSStefan Hajnoczi                     self.args.copy(), self.lineno, self.filename,
2754e66c9efSStefan Hajnoczi                     self, self.event_trans, self.event_exec)
276ad7443e4SLluís Vilanova
277650ab98dSLluís Vilanova    @staticmethod
2784e66c9efSStefan Hajnoczi    def build(line_str, lineno, filename):
279650ab98dSLluís Vilanova        """Build an Event instance from a string.
280650ab98dSLluís Vilanova
281650ab98dSLluís Vilanova        Parameters
282650ab98dSLluís Vilanova        ----------
283650ab98dSLluís Vilanova        line_str : str
284650ab98dSLluís Vilanova            Line describing the event.
2854e66c9efSStefan Hajnoczi        lineno : int
2864e66c9efSStefan Hajnoczi            Line number in input file.
2874e66c9efSStefan Hajnoczi        filename : str
2884e66c9efSStefan Hajnoczi            Path to input file.
289650ab98dSLluís Vilanova        """
290650ab98dSLluís Vilanova        m = Event._CRE.match(line_str)
291650ab98dSLluís Vilanova        assert m is not None
292650ab98dSLluís Vilanova        groups = m.groupdict('')
293650ab98dSLluís Vilanova
294650ab98dSLluís Vilanova        name = groups["name"]
295650ab98dSLluís Vilanova        props = groups["props"].split()
296650ab98dSLluís Vilanova        fmt = groups["fmt"]
297b2b36c22SLluís Vilanova        fmt_trans = groups["fmt_trans"]
298772f1b37SDaniel P. Berrangé        if fmt.find("%m") != -1 or fmt_trans.find("%m") != -1:
299772f1b37SDaniel P. Berrangé            raise ValueError("Event format '%m' is forbidden, pass the error "
300772f1b37SDaniel P. Berrangé                             "as an explicit trace argument")
3019f7ad79cSPhilippe Mathieu-Daudé        if fmt.endswith(r'\n"'):
3029f7ad79cSPhilippe Mathieu-Daudé            raise ValueError("Event format must not end with a newline "
3039f7ad79cSPhilippe Mathieu-Daudé                             "character")
304*4c2b6f32SPhilippe Mathieu-Daudé        if '\\n' in fmt:
305*4c2b6f32SPhilippe Mathieu-Daudé            raise ValueError("Event format must not use new line character")
306772f1b37SDaniel P. Berrangé
307b2b36c22SLluís Vilanova        if len(fmt_trans) > 0:
308b2b36c22SLluís Vilanova            fmt = [fmt_trans, fmt]
309650ab98dSLluís Vilanova        args = Arguments.build(groups["args"])
310650ab98dSLluís Vilanova
3110e2b9edfSPhilippe Mathieu-Daudé        return Event(name, props, fmt, args, lineno, filename)
312650ab98dSLluís Vilanova
313650ab98dSLluís Vilanova    def __repr__(self):
314650ab98dSLluís Vilanova        """Evaluable string representation for this object."""
315b2b36c22SLluís Vilanova        if isinstance(self.fmt, str):
316b2b36c22SLluís Vilanova            fmt = self.fmt
317b2b36c22SLluís Vilanova        else:
318b2b36c22SLluís Vilanova            fmt = "%s, %s" % (self.fmt[0], self.fmt[1])
319650ab98dSLluís Vilanova        return "Event('%s %s(%s) %s')" % (" ".join(self.properties),
320650ab98dSLluís Vilanova                                          self.name,
321650ab98dSLluís Vilanova                                          self.args,
322b2b36c22SLluís Vilanova                                          fmt)
323fb1a66bcSJon Emil Jahren    # Star matching on PRI is dangerous as one might have multiple
324fb1a66bcSJon Emil Jahren    # arguments with that format, hence the non-greedy version of it.
325e6d8e5e6SPaolo Bonzini    _FMT = re.compile(r"(%[\d\.]*\w+|%.*?PRI\S+)")
32623214429SLluís Vilanova
32723214429SLluís Vilanova    def formats(self):
3286e497fa1SStefan Hajnoczi        """List conversion specifiers in the argument print format string."""
32923214429SLluís Vilanova        assert not isinstance(self.fmt, list)
33023214429SLluís Vilanova        return self._FMT.findall(self.fmt)
33123214429SLluís Vilanova
3327d08f0daSLluís Vilanova    QEMU_TRACE               = "trace_%(name)s"
333864a2178SLluís Vilanova    QEMU_TRACE_NOCHECK       = "_nocheck__" + QEMU_TRACE
334707c8a98SLluís Vilanova    QEMU_TRACE_TCG           = QEMU_TRACE + "_tcg"
33593977402SDaniel P. Berrange    QEMU_DSTATE              = "_TRACE_%(NAME)s_DSTATE"
3363932ef3fSStefan Hajnoczi    QEMU_BACKEND_DSTATE      = "TRACE_%(NAME)s_BACKEND_DSTATE"
33779218be4SDaniel P. Berrange    QEMU_EVENT               = "_TRACE_%(NAME)s_EVENT"
3387d08f0daSLluís Vilanova
3397d08f0daSLluís Vilanova    def api(self, fmt=None):
3407d08f0daSLluís Vilanova        if fmt is None:
3417d08f0daSLluís Vilanova            fmt = Event.QEMU_TRACE
34293977402SDaniel P. Berrange        return fmt % {"name": self.name, "NAME": self.name.upper()}
3437d08f0daSLluís Vilanova
3447d08f0daSLluís Vilanova
34586b5aacfSDaniel P. Berrangédef read_events(fobj, fname):
346d1b97bceSDaniel P. Berrange    """Generate the output for the given (format, backends) pair.
347d1b97bceSDaniel P. Berrange
348d1b97bceSDaniel P. Berrange    Parameters
349d1b97bceSDaniel P. Berrange    ----------
350d1b97bceSDaniel P. Berrange    fobj : file
351d1b97bceSDaniel P. Berrange        Event description file.
35286b5aacfSDaniel P. Berrangé    fname : str
35386b5aacfSDaniel P. Berrangé        Name of event file
354d1b97bceSDaniel P. Berrange
355d1b97bceSDaniel P. Berrange    Returns a list of Event objects
356d1b97bceSDaniel P. Berrange    """
357d1b97bceSDaniel P. Berrange
358776ec96fSChristoph Seifert    events = []
3595069b561SStefan Hajnoczi    for lineno, line in enumerate(fobj, 1):
36077606363SDaniel P. Berrangé        if line[-1] != '\n':
36177606363SDaniel P. Berrangé            raise ValueError("%s does not end with a new line" % fname)
362650ab98dSLluís Vilanova        if not line.strip():
363650ab98dSLluís Vilanova            continue
364650ab98dSLluís Vilanova        if line.lstrip().startswith('#'):
365650ab98dSLluís Vilanova            continue
366776ec96fSChristoph Seifert
3675069b561SStefan Hajnoczi        try:
3684e66c9efSStefan Hajnoczi            event = Event.build(line, lineno, fname)
3695069b561SStefan Hajnoczi        except ValueError as e:
37086b5aacfSDaniel P. Berrangé            arg0 = 'Error at %s:%d: %s' % (fname, lineno, e.args[0])
3715069b561SStefan Hajnoczi            e.args = (arg0,) + e.args[1:]
3725069b561SStefan Hajnoczi            raise
373776ec96fSChristoph Seifert
374776ec96fSChristoph Seifert        events.append(event)
375776ec96fSChristoph Seifert
376776ec96fSChristoph Seifert    return events
377650ab98dSLluís Vilanova
378650ab98dSLluís Vilanova
379650ab98dSLluís Vilanovaclass TracetoolError (Exception):
380650ab98dSLluís Vilanova    """Exception for calls to generate."""
381650ab98dSLluís Vilanova    pass
382650ab98dSLluís Vilanova
383650ab98dSLluís Vilanova
384650ab98dSLluís Vilanovadef try_import(mod_name, attr_name=None, attr_default=None):
385650ab98dSLluís Vilanova    """Try to import a module and get an attribute from it.
386650ab98dSLluís Vilanova
387650ab98dSLluís Vilanova    Parameters
388650ab98dSLluís Vilanova    ----------
389650ab98dSLluís Vilanova    mod_name : str
390650ab98dSLluís Vilanova        Module name.
391650ab98dSLluís Vilanova    attr_name : str, optional
392650ab98dSLluís Vilanova        Name of an attribute in the module.
393650ab98dSLluís Vilanova    attr_default : optional
394650ab98dSLluís Vilanova        Default value if the attribute does not exist in the module.
395650ab98dSLluís Vilanova
396650ab98dSLluís Vilanova    Returns
397650ab98dSLluís Vilanova    -------
398650ab98dSLluís Vilanova    A pair indicating whether the module could be imported and the module or
399650ab98dSLluís Vilanova    object or attribute value.
400650ab98dSLluís Vilanova    """
401650ab98dSLluís Vilanova    try:
40245d6c787SStefan Hajnoczi        module = __import__(mod_name, globals(), locals(), ["__package__"])
403650ab98dSLluís Vilanova        if attr_name is None:
404650ab98dSLluís Vilanova            return True, module
405650ab98dSLluís Vilanova        return True, getattr(module, str(attr_name), attr_default)
406650ab98dSLluís Vilanova    except ImportError:
407650ab98dSLluís Vilanova        return False, None
408650ab98dSLluís Vilanova
409650ab98dSLluís Vilanova
41080dd5c49SDaniel P. Berrangedef generate(events, group, format, backends,
41152ef093aSLluís Vilanova             binary=None, probe_prefix=None):
4125b808275SLluís Vilanova    """Generate the output for the given (format, backends) pair.
413650ab98dSLluís Vilanova
414650ab98dSLluís Vilanova    Parameters
415650ab98dSLluís Vilanova    ----------
4169096b78aSDaniel P. Berrange    events : list
4179096b78aSDaniel P. Berrange        list of Event objects to generate for
41880dd5c49SDaniel P. Berrange    group: str
41980dd5c49SDaniel P. Berrange        Name of the tracing group
420650ab98dSLluís Vilanova    format : str
421650ab98dSLluís Vilanova        Output format name.
4225b808275SLluís Vilanova    backends : list
4235b808275SLluís Vilanova        Output backend names.
42452ef093aSLluís Vilanova    binary : str or None
42552ef093aSLluís Vilanova        See tracetool.backend.dtrace.BINARY.
42652ef093aSLluís Vilanova    probe_prefix : str or None
42752ef093aSLluís Vilanova        See tracetool.backend.dtrace.PROBEPREFIX.
428650ab98dSLluís Vilanova    """
429650ab98dSLluís Vilanova    # fix strange python error (UnboundLocalError tracetool)
430650ab98dSLluís Vilanova    import tracetool
431650ab98dSLluís Vilanova
432650ab98dSLluís Vilanova    format = str(format)
433403e11edSStefan Hajnoczi    if len(format) == 0:
434650ab98dSLluís Vilanova        raise TracetoolError("format not set")
43553158adcSLluís Vilanova    if not tracetool.format.exists(format):
436650ab98dSLluís Vilanova        raise TracetoolError("unknown format: %s" % format)
437650ab98dSLluís Vilanova
438403e11edSStefan Hajnoczi    if len(backends) == 0:
4395b808275SLluís Vilanova        raise TracetoolError("no backends specified")
4405b808275SLluís Vilanova    for backend in backends:
44153158adcSLluís Vilanova        if not tracetool.backend.exists(backend):
442650ab98dSLluís Vilanova            raise TracetoolError("unknown backend: %s" % backend)
4435b808275SLluís Vilanova    backend = tracetool.backend.Wrapper(backends, format)
444650ab98dSLluís Vilanova
44552ef093aSLluís Vilanova    import tracetool.backend.dtrace
44652ef093aSLluís Vilanova    tracetool.backend.dtrace.BINARY = binary
44752ef093aSLluís Vilanova    tracetool.backend.dtrace.PROBEPREFIX = probe_prefix
44852ef093aSLluís Vilanova
44980dd5c49SDaniel P. Berrange    tracetool.format.generate(events, format, backend, group)
450