]>
git.proxmox.com Git - mirror_qemu.git/blob - scripts/tracetool/__init__.py
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")
44 # We only want to allow standard C types or fixed sized
45 # integer types. We don't want QEMU specific types
46 # as we can't assume trace backends can resolve all the
71 # Magic substitution is done by tracetool
75 def validate_type(name
):
76 bits
= name
.split(" ")
78 bit
= re
.sub("\*", "", bit
)
83 if bit
not in ALLOWED_TYPES
:
84 raise ValueError("Argument type '%s' is not in whitelist. "
85 "Only standard C types and fixed size integer "
86 "types should be used. struct, union, and "
87 "other complex pointer types should be "
88 "declared as 'void *'" % name
)
91 """Event arguments description."""
93 def __init__(self
, args
):
98 List of (type, name) tuples or Arguments objects.
102 if isinstance(arg
, Arguments
):
103 self
._args
.extend(arg
._args
)
105 self
._args
.append(arg
)
108 """Create a new copy."""
109 return Arguments(list(self
._args
))
113 """Build and Arguments instance from an argument string.
118 String describing the event arguments.
121 for arg
in arg_str
.split(","):
124 raise ValueError("Empty argument (did you forget to use 'void'?)")
129 arg_type
, identifier
= arg
.rsplit('*', 1)
131 identifier
= identifier
.strip()
133 arg_type
, identifier
= arg
.rsplit(None, 1)
135 validate_type(arg_type
)
136 res
.append((arg_type
, identifier
))
137 return Arguments(res
)
139 def __getitem__(self
, index
):
140 if isinstance(index
, slice):
141 return Arguments(self
._args
[index
])
143 return self
._args
[index
]
146 """Iterate over the (type, name) pairs."""
147 return iter(self
._args
)
150 """Number of arguments."""
151 return len(self
._args
)
154 """String suitable for declaring function arguments."""
155 if len(self
._args
) == 0:
158 return ", ".join([ " ".join([t
, n
]) for t
,n
in self
._args
])
161 """Evaluable string representation for this object."""
162 return "Arguments(\"%s\")" % str(self
)
165 """List of argument names."""
166 return [ name
for _
, name
in self
._args
]
169 """List of argument types."""
170 return [ type_
for type_
, _
in self
._args
]
173 """List of argument names casted to their type."""
174 return ["(%s)%s" % (type_
, name
) for type_
, name
in self
._args
]
176 def transform(self
, *trans
):
177 """Return a new Arguments instance with transformed types.
179 The types in the resulting Arguments instance are transformed according
180 to tracetool.transform.transform_type.
183 for type_
, name
in self
._args
:
184 res
.append((tracetool
.transform
.transform_type(type_
, *trans
),
186 return Arguments(res
)
190 """Event description.
197 The event format string.
198 properties : set(str)
199 Properties of the event.
205 _CRE
= re
.compile("((?P<props>[\w\s]+)\s+)?"
207 "\((?P<args>[^)]*)\)"
209 "(?:(?:(?P<fmt_trans>\".+),)?\s*(?P<fmt>\".+))?"
212 _VALID_PROPS
= set(["disable", "tcg", "tcg-trans", "tcg-exec", "vcpu"])
214 def __init__(self
, name
, props
, fmt
, args
, orig
=None,
215 event_trans
=None, event_exec
=None):
223 fmt : str, list of str
224 Event printing format string(s).
228 Original Event before transformation/generation.
229 event_trans : Event or None
230 Generated translation-time event ("tcg" property).
231 event_exec : Event or None
232 Generated execution-time event ("tcg" property).
236 self
.properties
= props
239 self
.event_trans
= event_trans
240 self
.event_exec
= event_exec
243 raise ValueError("Event '%s' has more than maximum permitted "
244 "argument count" % name
)
247 self
.original
= weakref
.ref(self
)
251 unknown_props
= set(self
.properties
) - self
._VALID
_PROPS
252 if len(unknown_props
) > 0:
253 raise ValueError("Unknown properties: %s"
254 % ", ".join(unknown_props
))
255 assert isinstance(self
.fmt
, str) or len(self
.fmt
) == 2
258 """Create a new copy."""
259 return Event(self
.name
, list(self
.properties
), self
.fmt
,
260 self
.args
.copy(), self
, self
.event_trans
, self
.event_exec
)
264 """Build an Event instance from a string.
269 Line describing the event.
271 m
= Event
._CRE
.match(line_str
)
273 groups
= m
.groupdict('')
275 name
= groups
["name"]
276 props
= groups
["props"].split()
278 fmt_trans
= groups
["fmt_trans"]
279 if len(fmt_trans
) > 0:
280 fmt
= [fmt_trans
, fmt
]
281 args
= Arguments
.build(groups
["args"])
283 if "tcg-trans" in props
:
284 raise ValueError("Invalid property 'tcg-trans'")
285 if "tcg-exec" in props
:
286 raise ValueError("Invalid property 'tcg-exec'")
287 if "tcg" not in props
and not isinstance(fmt
, str):
288 raise ValueError("Only events with 'tcg' property can have two format strings")
289 if "tcg" in props
and isinstance(fmt
, str):
290 raise ValueError("Events with 'tcg' property must have two format strings")
292 event
= Event(name
, props
, fmt
, args
)
294 # add implicit arguments when using the 'vcpu' property
295 import tracetool
.vcpu
296 event
= tracetool
.vcpu
.transform_event(event
)
301 """Evaluable string representation for this object."""
302 if isinstance(self
.fmt
, str):
305 fmt
= "%s, %s" % (self
.fmt
[0], self
.fmt
[1])
306 return "Event('%s %s(%s) %s')" % (" ".join(self
.properties
),
310 # Star matching on PRI is dangerous as one might have multiple
311 # arguments with that format, hence the non-greedy version of it.
312 _FMT
= re
.compile("(%[\d\.]*\w+|%.*?PRI\S+)")
315 """List conversion specifiers in the argument print format string."""
316 assert not isinstance(self
.fmt
, list)
317 return self
._FMT
.findall(self
.fmt
)
319 QEMU_TRACE
= "trace_%(name)s"
320 QEMU_TRACE_NOCHECK
= "_nocheck__" + QEMU_TRACE
321 QEMU_TRACE_TCG
= QEMU_TRACE
+ "_tcg"
322 QEMU_DSTATE
= "_TRACE_%(NAME)s_DSTATE"
323 QEMU_BACKEND_DSTATE
= "TRACE_%(NAME)s_BACKEND_DSTATE"
324 QEMU_EVENT
= "_TRACE_%(NAME)s_EVENT"
326 def api(self
, fmt
=None):
328 fmt
= Event
.QEMU_TRACE
329 return fmt
% {"name": self
.name
, "NAME": self
.name
.upper()}
331 def transform(self
, *trans
):
332 """Return a new Event with transformed Arguments."""
333 return Event(self
.name
,
334 list(self
.properties
),
336 self
.args
.transform(*trans
),
340 def read_events(fobj
, fname
):
341 """Generate the output for the given (format, backends) pair.
346 Event description file.
350 Returns a list of Event objects
354 for lineno
, line
in enumerate(fobj
, 1):
357 if line
.lstrip().startswith('#'):
361 event
= Event
.build(line
)
362 except ValueError as e
:
363 arg0
= 'Error at %s:%d: %s' % (fname
, lineno
, e
.args
[0])
364 e
.args
= (arg0
,) + e
.args
[1:]
367 # transform TCG-enabled events
368 if "tcg" not in event
.properties
:
371 event_trans
= event
.copy()
372 event_trans
.name
+= "_trans"
373 event_trans
.properties
+= ["tcg-trans"]
374 event_trans
.fmt
= event
.fmt
[0]
375 # ignore TCG arguments
377 for atrans
, aorig
in zip(
378 event_trans
.transform(tracetool
.transform
.TCG_2_HOST
).args
,
381 args_trans
.append(atrans
)
382 event_trans
.args
= Arguments(args_trans
)
384 event_exec
= event
.copy()
385 event_exec
.name
+= "_exec"
386 event_exec
.properties
+= ["tcg-exec"]
387 event_exec
.fmt
= event
.fmt
[1]
388 event_exec
.args
= event_exec
.args
.transform(tracetool
.transform
.TCG_2_HOST
)
390 new_event
= [event_trans
, event_exec
]
391 event
.event_trans
, event
.event_exec
= new_event
393 events
.extend(new_event
)
398 class TracetoolError (Exception):
399 """Exception for calls to generate."""
403 def try_import(mod_name
, attr_name
=None, attr_default
=None):
404 """Try to import a module and get an attribute from it.
410 attr_name : str, optional
411 Name of an attribute in the module.
412 attr_default : optional
413 Default value if the attribute does not exist in the module.
417 A pair indicating whether the module could be imported and the module or
418 object or attribute value.
421 module
= __import__(mod_name
, globals(), locals(), ["__package__"])
422 if attr_name
is None:
424 return True, getattr(module
, str(attr_name
), attr_default
)
429 def generate(events
, group
, format
, backends
,
430 binary
=None, probe_prefix
=None):
431 """Generate the output for the given (format, backends) pair.
436 list of Event objects to generate for
438 Name of the tracing group
442 Output backend names.
444 See tracetool.backend.dtrace.BINARY.
445 probe_prefix : str or None
446 See tracetool.backend.dtrace.PROBEPREFIX.
448 # fix strange python error (UnboundLocalError tracetool)
453 raise TracetoolError("format not set")
454 if not tracetool
.format
.exists(format
):
455 raise TracetoolError("unknown format: %s" % format
)
457 if len(backends
) is 0:
458 raise TracetoolError("no backends specified")
459 for backend
in backends
:
460 if not tracetool
.backend
.exists(backend
):
461 raise TracetoolError("unknown backend: %s" % backend
)
462 backend
= tracetool
.backend
.Wrapper(backends
, format
)
464 import tracetool
.backend
.dtrace
465 tracetool
.backend
.dtrace
.BINARY
= binary
466 tracetool
.backend
.dtrace
.PROBEPREFIX
= probe_prefix
468 tracetool
.format
.generate(events
, format
, backend
, group
)