2 # -*- coding: utf-8 -*-
5 Machinery for generating tracing-related intermediate files.
8 __author__
= "Lluís Vilanova <vilanova@ac.upc.edu>"
9 __copyright__
= "Copyright 2012-2017, Lluís Vilanova <vilanova@ac.upc.edu>"
10 __license__
= "GPL version 2 or (at your option) any later version"
12 __maintainer__
= "Stefan Hajnoczi"
13 __email__
= "stefanha@linux.vnet.ibm.com"
20 import tracetool
.format
21 import tracetool
.backend
22 import tracetool
.transform
25 def error_write(*lines
):
26 """Write a set of error lines."""
27 sys
.stderr
.writelines("\n".join(lines
) + "\n")
30 """Write a set of error lines and exit."""
35 def out(*lines
, **kwargs
):
36 """Write a set of output lines.
38 You can use kwargs as a shorthand for mapping variables when formating all
41 lines
= [ l
% kwargs
for l
in lines
]
42 sys
.stdout
.writelines("\n".join(lines
) + "\n")
46 """Event arguments description."""
48 def __init__(self
, args
):
53 List of (type, name) tuples or Arguments objects.
57 if isinstance(arg
, Arguments
):
58 self
._args
.extend(arg
._args
)
60 self
._args
.append(arg
)
63 """Create a new copy."""
64 return Arguments(list(self
._args
))
68 """Build and Arguments instance from an argument string.
73 String describing the event arguments.
76 for arg
in arg_str
.split(","):
79 raise ValueError("Empty argument (did you forget to use 'void'?)")
84 arg_type
, identifier
= arg
.rsplit('*', 1)
86 identifier
= identifier
.strip()
88 arg_type
, identifier
= arg
.rsplit(None, 1)
90 res
.append((arg_type
, identifier
))
93 def __getitem__(self
, index
):
94 if isinstance(index
, slice):
95 return Arguments(self
._args
[index
])
97 return self
._args
[index
]
100 """Iterate over the (type, name) pairs."""
101 return iter(self
._args
)
104 """Number of arguments."""
105 return len(self
._args
)
108 """String suitable for declaring function arguments."""
109 if len(self
._args
) == 0:
112 return ", ".join([ " ".join([t
, n
]) for t
,n
in self
._args
])
115 """Evaluable string representation for this object."""
116 return "Arguments(\"%s\")" % str(self
)
119 """List of argument names."""
120 return [ name
for _
, name
in self
._args
]
123 """List of argument types."""
124 return [ type_
for type_
, _
in self
._args
]
127 """List of argument names casted to their type."""
128 return ["(%s)%s" % (type_
, name
) for type_
, name
in self
._args
]
130 def transform(self
, *trans
):
131 """Return a new Arguments instance with transformed types.
133 The types in the resulting Arguments instance are transformed according
134 to tracetool.transform.transform_type.
137 for type_
, name
in self
._args
:
138 res
.append((tracetool
.transform
.transform_type(type_
, *trans
),
140 return Arguments(res
)
144 """Event description.
151 The event format string.
152 properties : set(str)
153 Properties of the event.
159 _CRE
= re
.compile("((?P<props>[\w\s]+)\s+)?"
161 "\((?P<args>[^)]*)\)"
163 "(?:(?:(?P<fmt_trans>\".+),)?\s*(?P<fmt>\".+))?"
166 _VALID_PROPS
= set(["disable", "tcg", "tcg-trans", "tcg-exec", "vcpu"])
168 def __init__(self
, name
, props
, fmt
, args
, orig
=None,
169 event_trans
=None, event_exec
=None):
177 fmt : str, list of str
178 Event printing format string(s).
182 Original Event before transformation/generation.
183 event_trans : Event or None
184 Generated translation-time event ("tcg" property).
185 event_exec : Event or None
186 Generated execution-time event ("tcg" property).
190 self
.properties
= props
193 self
.event_trans
= event_trans
194 self
.event_exec
= event_exec
197 raise ValueError("Event '%s' has more than maximum permitted "
198 "argument count" % name
)
201 self
.original
= weakref
.ref(self
)
205 unknown_props
= set(self
.properties
) - self
._VALID
_PROPS
206 if len(unknown_props
) > 0:
207 raise ValueError("Unknown properties: %s"
208 % ", ".join(unknown_props
))
209 assert isinstance(self
.fmt
, str) or len(self
.fmt
) == 2
212 """Create a new copy."""
213 return Event(self
.name
, list(self
.properties
), self
.fmt
,
214 self
.args
.copy(), self
, self
.event_trans
, self
.event_exec
)
218 """Build an Event instance from a string.
223 Line describing the event.
225 m
= Event
._CRE
.match(line_str
)
227 groups
= m
.groupdict('')
229 name
= groups
["name"]
230 props
= groups
["props"].split()
232 fmt_trans
= groups
["fmt_trans"]
233 if len(fmt_trans
) > 0:
234 fmt
= [fmt_trans
, fmt
]
235 args
= Arguments
.build(groups
["args"])
237 if "tcg-trans" in props
:
238 raise ValueError("Invalid property 'tcg-trans'")
239 if "tcg-exec" in props
:
240 raise ValueError("Invalid property 'tcg-exec'")
241 if "tcg" not in props
and not isinstance(fmt
, str):
242 raise ValueError("Only events with 'tcg' property can have two format strings")
243 if "tcg" in props
and isinstance(fmt
, str):
244 raise ValueError("Events with 'tcg' property must have two format strings")
246 event
= Event(name
, props
, fmt
, args
)
248 # add implicit arguments when using the 'vcpu' property
249 import tracetool
.vcpu
250 event
= tracetool
.vcpu
.transform_event(event
)
255 """Evaluable string representation for this object."""
256 if isinstance(self
.fmt
, str):
259 fmt
= "%s, %s" % (self
.fmt
[0], self
.fmt
[1])
260 return "Event('%s %s(%s) %s')" % (" ".join(self
.properties
),
264 # Star matching on PRI is dangerous as one might have multiple
265 # arguments with that format, hence the non-greedy version of it.
266 _FMT
= re
.compile("(%[\d\.]*\w+|%.*?PRI\S+)")
269 """List conversion specifiers in the argument print format string."""
270 assert not isinstance(self
.fmt
, list)
271 return self
._FMT
.findall(self
.fmt
)
273 QEMU_TRACE
= "trace_%(name)s"
274 QEMU_TRACE_NOCHECK
= "_nocheck__" + QEMU_TRACE
275 QEMU_TRACE_TCG
= QEMU_TRACE
+ "_tcg"
276 QEMU_DSTATE
= "_TRACE_%(NAME)s_DSTATE"
277 QEMU_BACKEND_DSTATE
= "TRACE_%(NAME)s_BACKEND_DSTATE"
278 QEMU_EVENT
= "_TRACE_%(NAME)s_EVENT"
280 def api(self
, fmt
=None):
282 fmt
= Event
.QEMU_TRACE
283 return fmt
% {"name": self
.name
, "NAME": self
.name
.upper()}
285 def transform(self
, *trans
):
286 """Return a new Event with transformed Arguments."""
287 return Event(self
.name
,
288 list(self
.properties
),
290 self
.args
.transform(*trans
),
294 def read_events(fobj
):
295 """Generate the output for the given (format, backends) pair.
300 Event description file.
302 Returns a list of Event objects
306 for lineno
, line
in enumerate(fobj
, 1):
309 if line
.lstrip().startswith('#'):
313 event
= Event
.build(line
)
314 except ValueError as e
:
315 arg0
= 'Error on line %d: %s' % (lineno
, e
.args
[0])
316 e
.args
= (arg0
,) + e
.args
[1:]
319 # transform TCG-enabled events
320 if "tcg" not in event
.properties
:
323 event_trans
= event
.copy()
324 event_trans
.name
+= "_trans"
325 event_trans
.properties
+= ["tcg-trans"]
326 event_trans
.fmt
= event
.fmt
[0]
327 # ignore TCG arguments
329 for atrans
, aorig
in zip(
330 event_trans
.transform(tracetool
.transform
.TCG_2_HOST
).args
,
333 args_trans
.append(atrans
)
334 event_trans
.args
= Arguments(args_trans
)
336 event_exec
= event
.copy()
337 event_exec
.name
+= "_exec"
338 event_exec
.properties
+= ["tcg-exec"]
339 event_exec
.fmt
= event
.fmt
[1]
340 event_exec
.args
= event_exec
.args
.transform(tracetool
.transform
.TCG_2_HOST
)
342 new_event
= [event_trans
, event_exec
]
343 event
.event_trans
, event
.event_exec
= new_event
345 events
.extend(new_event
)
350 class TracetoolError (Exception):
351 """Exception for calls to generate."""
355 def try_import(mod_name
, attr_name
=None, attr_default
=None):
356 """Try to import a module and get an attribute from it.
362 attr_name : str, optional
363 Name of an attribute in the module.
364 attr_default : optional
365 Default value if the attribute does not exist in the module.
369 A pair indicating whether the module could be imported and the module or
370 object or attribute value.
373 module
= __import__(mod_name
, globals(), locals(), ["__package__"])
374 if attr_name
is None:
376 return True, getattr(module
, str(attr_name
), attr_default
)
381 def generate(events
, group
, format
, backends
,
382 binary
=None, probe_prefix
=None):
383 """Generate the output for the given (format, backends) pair.
388 list of Event objects to generate for
390 Name of the tracing group
394 Output backend names.
396 See tracetool.backend.dtrace.BINARY.
397 probe_prefix : str or None
398 See tracetool.backend.dtrace.PROBEPREFIX.
400 # fix strange python error (UnboundLocalError tracetool)
405 raise TracetoolError("format not set")
406 if not tracetool
.format
.exists(format
):
407 raise TracetoolError("unknown format: %s" % format
)
409 if len(backends
) is 0:
410 raise TracetoolError("no backends specified")
411 for backend
in backends
:
412 if not tracetool
.backend
.exists(backend
):
413 raise TracetoolError("unknown backend: %s" % backend
)
414 backend
= tracetool
.backend
.Wrapper(backends
, format
)
416 import tracetool
.backend
.dtrace
417 tracetool
.backend
.dtrace
.BINARY
= binary
418 tracetool
.backend
.dtrace
.PROBEPREFIX
= probe_prefix
420 tracetool
.format
.generate(events
, format
, backend
, group
)