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(","):
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 raise ValueError("Event '%s' has more than maximum permitted "
196 "argument count" % name
)
199 self
.original
= weakref
.ref(self
)
203 unknown_props
= set(self
.properties
) - self
._VALID
_PROPS
204 if len(unknown_props
) > 0:
205 raise ValueError("Unknown properties: %s"
206 % ", ".join(unknown_props
))
207 assert isinstance(self
.fmt
, str) or len(self
.fmt
) == 2
210 """Create a new copy."""
211 return Event(self
.name
, list(self
.properties
), self
.fmt
,
212 self
.args
.copy(), self
, self
.event_trans
, self
.event_exec
)
216 """Build an Event instance from a string.
221 Line describing the event.
223 m
= Event
._CRE
.match(line_str
)
225 groups
= m
.groupdict('')
227 name
= groups
["name"]
228 props
= groups
["props"].split()
230 fmt_trans
= groups
["fmt_trans"]
231 if len(fmt_trans
) > 0:
232 fmt
= [fmt_trans
, fmt
]
233 args
= Arguments
.build(groups
["args"])
235 if "tcg-trans" in props
:
236 raise ValueError("Invalid property 'tcg-trans'")
237 if "tcg-exec" in props
:
238 raise ValueError("Invalid property 'tcg-exec'")
239 if "tcg" not in props
and not isinstance(fmt
, str):
240 raise ValueError("Only events with 'tcg' property can have two formats")
241 if "tcg" in props
and isinstance(fmt
, str):
242 raise ValueError("Events with 'tcg' property must have two formats")
244 event
= Event(name
, props
, fmt
, args
)
246 # add implicit arguments when using the 'vcpu' property
247 import tracetool
.vcpu
248 event
= tracetool
.vcpu
.transform_event(event
)
253 """Evaluable string representation for this object."""
254 if isinstance(self
.fmt
, str):
257 fmt
= "%s, %s" % (self
.fmt
[0], self
.fmt
[1])
258 return "Event('%s %s(%s) %s')" % (" ".join(self
.properties
),
263 _FMT
= re
.compile("(%[\d\.]*\w+|%.*PRI\S+)")
266 """List of argument print formats."""
267 assert not isinstance(self
.fmt
, list)
268 return self
._FMT
.findall(self
.fmt
)
270 QEMU_TRACE
= "trace_%(name)s"
271 QEMU_TRACE_NOCHECK
= "_nocheck__" + QEMU_TRACE
272 QEMU_TRACE_TCG
= QEMU_TRACE
+ "_tcg"
273 QEMU_DSTATE
= "_TRACE_%(NAME)s_DSTATE"
274 QEMU_BACKEND_DSTATE
= "TRACE_%(NAME)s_BACKEND_DSTATE"
275 QEMU_EVENT
= "_TRACE_%(NAME)s_EVENT"
277 def api(self
, fmt
=None):
279 fmt
= Event
.QEMU_TRACE
280 return fmt
% {"name": self
.name
, "NAME": self
.name
.upper()}
282 def transform(self
, *trans
):
283 """Return a new Event with transformed Arguments."""
284 return Event(self
.name
,
285 list(self
.properties
),
287 self
.args
.transform(*trans
),
291 def read_events(fobj
):
292 """Generate the output for the given (format, backends) pair.
297 Event description file.
299 Returns a list of Event objects
306 if line
.lstrip().startswith('#'):
309 event
= Event
.build(line
)
311 # transform TCG-enabled events
312 if "tcg" not in event
.properties
:
315 event_trans
= event
.copy()
316 event_trans
.name
+= "_trans"
317 event_trans
.properties
+= ["tcg-trans"]
318 event_trans
.fmt
= event
.fmt
[0]
319 # ignore TCG arguments
321 for atrans
, aorig
in zip(
322 event_trans
.transform(tracetool
.transform
.TCG_2_HOST
).args
,
325 args_trans
.append(atrans
)
326 event_trans
.args
= Arguments(args_trans
)
328 event_exec
= event
.copy()
329 event_exec
.name
+= "_exec"
330 event_exec
.properties
+= ["tcg-exec"]
331 event_exec
.fmt
= event
.fmt
[1]
332 event_exec
.args
= event_exec
.args
.transform(tracetool
.transform
.TCG_2_HOST
)
334 new_event
= [event_trans
, event_exec
]
335 event
.event_trans
, event
.event_exec
= new_event
337 events
.extend(new_event
)
342 class TracetoolError (Exception):
343 """Exception for calls to generate."""
347 def try_import(mod_name
, attr_name
=None, attr_default
=None):
348 """Try to import a module and get an attribute from it.
354 attr_name : str, optional
355 Name of an attribute in the module.
356 attr_default : optional
357 Default value if the attribute does not exist in the module.
361 A pair indicating whether the module could be imported and the module or
362 object or attribute value.
365 module
= __import__(mod_name
, globals(), locals(), ["__package__"])
366 if attr_name
is None:
368 return True, getattr(module
, str(attr_name
), attr_default
)
373 def generate(events
, group
, format
, backends
,
374 binary
=None, probe_prefix
=None):
375 """Generate the output for the given (format, backends) pair.
380 list of Event objects to generate for
382 Name of the tracing group
386 Output backend names.
388 See tracetool.backend.dtrace.BINARY.
389 probe_prefix : str or None
390 See tracetool.backend.dtrace.PROBEPREFIX.
392 # fix strange python error (UnboundLocalError tracetool)
397 raise TracetoolError("format not set")
398 if not tracetool
.format
.exists(format
):
399 raise TracetoolError("unknown format: %s" % format
)
401 if len(backends
) is 0:
402 raise TracetoolError("no backends specified")
403 for backend
in backends
:
404 if not tracetool
.backend
.exists(backend
):
405 raise TracetoolError("unknown backend: %s" % backend
)
406 backend
= tracetool
.backend
.Wrapper(backends
, format
)
408 import tracetool
.backend
.dtrace
409 tracetool
.backend
.dtrace
.BINARY
= binary
410 tracetool
.backend
.dtrace
.PROBEPREFIX
= probe_prefix
412 tracetool
.format
.generate(events
, format
, backend
, group
)