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-2016, 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(","):
82 arg_type
, identifier
= arg
.rsplit('*', 1)
84 identifier
= identifier
.strip()
86 arg_type
, identifier
= arg
.rsplit(None, 1)
88 res
.append((arg_type
, identifier
))
91 def __getitem__(self
, index
):
92 if isinstance(index
, slice):
93 return Arguments(self
._args
[index
])
95 return self
._args
[index
]
98 """Iterate over the (type, name) pairs."""
99 return iter(self
._args
)
102 """Number of arguments."""
103 return len(self
._args
)
106 """String suitable for declaring function arguments."""
107 if len(self
._args
) == 0:
110 return ", ".join([ " ".join([t
, n
]) for t
,n
in self
._args
])
113 """Evaluable string representation for this object."""
114 return "Arguments(\"%s\")" % str(self
)
117 """List of argument names."""
118 return [ name
for _
, name
in self
._args
]
121 """List of argument types."""
122 return [ type_
for type_
, _
in self
._args
]
125 """List of argument names casted to their type."""
126 return ["(%s)%s" % (type_
, name
) for type_
, name
in self
._args
]
128 def transform(self
, *trans
):
129 """Return a new Arguments instance with transformed types.
131 The types in the resulting Arguments instance are transformed according
132 to tracetool.transform.transform_type.
135 for type_
, name
in self
._args
:
136 res
.append((tracetool
.transform
.transform_type(type_
, *trans
),
138 return Arguments(res
)
142 """Event description.
149 The event format string.
150 properties : set(str)
151 Properties of the event.
157 _CRE
= re
.compile("((?P<props>[\w\s]+)\s+)?"
159 "\((?P<args>[^)]*)\)"
161 "(?:(?:(?P<fmt_trans>\".+),)?\s*(?P<fmt>\".+))?"
164 _VALID_PROPS
= set(["disable", "tcg", "tcg-trans", "tcg-exec", "vcpu"])
166 def __init__(self
, name
, props
, fmt
, args
, orig
=None,
167 event_trans
=None, event_exec
=None):
175 fmt : str, list of str
176 Event printing format (or formats).
180 Original Event before transformation/generation.
181 event_trans : Event or None
182 Generated translation-time event ("tcg" property).
183 event_exec : Event or None
184 Generated execution-time event ("tcg" property).
188 self
.properties
= props
191 self
.event_trans
= event_trans
192 self
.event_exec
= event_exec
195 self
.original
= weakref
.ref(self
)
199 unknown_props
= set(self
.properties
) - self
._VALID
_PROPS
200 if len(unknown_props
) > 0:
201 raise ValueError("Unknown properties: %s"
202 % ", ".join(unknown_props
))
203 assert isinstance(self
.fmt
, str) or len(self
.fmt
) == 2
206 """Create a new copy."""
207 return Event(self
.name
, list(self
.properties
), self
.fmt
,
208 self
.args
.copy(), self
, self
.event_trans
, self
.event_exec
)
212 """Build an Event instance from a string.
217 Line describing the event.
219 m
= Event
._CRE
.match(line_str
)
221 groups
= m
.groupdict('')
223 name
= groups
["name"]
224 props
= groups
["props"].split()
226 fmt_trans
= groups
["fmt_trans"]
227 if len(fmt_trans
) > 0:
228 fmt
= [fmt_trans
, fmt
]
229 args
= Arguments
.build(groups
["args"])
231 if "tcg-trans" in props
:
232 raise ValueError("Invalid property 'tcg-trans'")
233 if "tcg-exec" in props
:
234 raise ValueError("Invalid property 'tcg-exec'")
235 if "tcg" not in props
and not isinstance(fmt
, str):
236 raise ValueError("Only events with 'tcg' property can have two formats")
237 if "tcg" in props
and isinstance(fmt
, str):
238 raise ValueError("Events with 'tcg' property must have two formats")
240 event
= Event(name
, props
, fmt
, args
)
242 # add implicit arguments when using the 'vcpu' property
243 import tracetool
.vcpu
244 event
= tracetool
.vcpu
.transform_event(event
)
249 """Evaluable string representation for this object."""
250 if isinstance(self
.fmt
, str):
253 fmt
= "%s, %s" % (self
.fmt
[0], self
.fmt
[1])
254 return "Event('%s %s(%s) %s')" % (" ".join(self
.properties
),
259 _FMT
= re
.compile("(%[\d\.]*\w+|%.*PRI\S+)")
262 """List of argument print formats."""
263 assert not isinstance(self
.fmt
, list)
264 return self
._FMT
.findall(self
.fmt
)
266 QEMU_TRACE
= "trace_%(name)s"
267 QEMU_TRACE_TCG
= QEMU_TRACE
+ "_tcg"
268 QEMU_DSTATE
= "_TRACE_%(NAME)s_DSTATE"
269 QEMU_EVENT
= "_TRACE_%(NAME)s_EVENT"
271 def api(self
, fmt
=None):
273 fmt
= Event
.QEMU_TRACE
274 return fmt
% {"name": self
.name
, "NAME": self
.name
.upper()}
276 def transform(self
, *trans
):
277 """Return a new Event with transformed Arguments."""
278 return Event(self
.name
,
279 list(self
.properties
),
281 self
.args
.transform(*trans
),
285 def read_events(fobj
):
286 """Generate the output for the given (format, backends) pair.
291 Event description file.
293 Returns a list of Event objects
300 if line
.lstrip().startswith('#'):
303 event
= Event
.build(line
)
305 # transform TCG-enabled events
306 if "tcg" not in event
.properties
:
309 event_trans
= event
.copy()
310 event_trans
.name
+= "_trans"
311 event_trans
.properties
+= ["tcg-trans"]
312 event_trans
.fmt
= event
.fmt
[0]
313 # ignore TCG arguments
315 for atrans
, aorig
in zip(
316 event_trans
.transform(tracetool
.transform
.TCG_2_HOST
).args
,
319 args_trans
.append(atrans
)
320 event_trans
.args
= Arguments(args_trans
)
322 event_exec
= event
.copy()
323 event_exec
.name
+= "_exec"
324 event_exec
.properties
+= ["tcg-exec"]
325 event_exec
.fmt
= event
.fmt
[1]
326 event_exec
.args
= event_exec
.args
.transform(tracetool
.transform
.TCG_2_HOST
)
328 new_event
= [event_trans
, event_exec
]
329 event
.event_trans
, event
.event_exec
= new_event
331 events
.extend(new_event
)
336 class TracetoolError (Exception):
337 """Exception for calls to generate."""
341 def try_import(mod_name
, attr_name
=None, attr_default
=None):
342 """Try to import a module and get an attribute from it.
348 attr_name : str, optional
349 Name of an attribute in the module.
350 attr_default : optional
351 Default value if the attribute does not exist in the module.
355 A pair indicating whether the module could be imported and the module or
356 object or attribute value.
359 module
= __import__(mod_name
, globals(), locals(), ["__package__"])
360 if attr_name
is None:
362 return True, getattr(module
, str(attr_name
), attr_default
)
367 def generate(events
, group
, format
, backends
,
368 binary
=None, probe_prefix
=None):
369 """Generate the output for the given (format, backends) pair.
374 list of Event objects to generate for
376 Name of the tracing group
380 Output backend names.
382 See tracetool.backend.dtrace.BINARY.
383 probe_prefix : str or None
384 See tracetool.backend.dtrace.PROBEPREFIX.
386 # fix strange python error (UnboundLocalError tracetool)
391 raise TracetoolError("format not set")
392 if not tracetool
.format
.exists(format
):
393 raise TracetoolError("unknown format: %s" % format
)
395 if len(backends
) is 0:
396 raise TracetoolError("no backends specified")
397 for backend
in backends
:
398 if not tracetool
.backend
.exists(backend
):
399 raise TracetoolError("unknown backend: %s" % backend
)
400 backend
= tracetool
.backend
.Wrapper(backends
, format
)
402 import tracetool
.backend
.dtrace
403 tracetool
.backend
.dtrace
.BINARY
= binary
404 tracetool
.backend
.dtrace
.PROBEPREFIX
= probe_prefix
406 tracetool
.format
.generate(events
, format
, backend
, group
)