__init__.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. Machinery for generating tracing-related intermediate files.
  5. """
  6. __author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
  7. __copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>"
  8. __license__ = "GPL version 2 or (at your option) any later version"
  9. __maintainer__ = "Stefan Hajnoczi"
  10. __email__ = "stefanha@linux.vnet.ibm.com"
  11. import re
  12. import sys
  13. import tracetool.format
  14. import tracetool.backend
  15. def error_write(*lines):
  16. """Write a set of error lines."""
  17. sys.stderr.writelines("\n".join(lines) + "\n")
  18. def error(*lines):
  19. """Write a set of error lines and exit."""
  20. error_write(*lines)
  21. sys.exit(1)
  22. def out(*lines, **kwargs):
  23. """Write a set of output lines.
  24. You can use kwargs as a shorthand for mapping variables when formating all
  25. the strings in lines.
  26. """
  27. lines = [ l % kwargs for l in lines ]
  28. sys.stdout.writelines("\n".join(lines) + "\n")
  29. class Arguments:
  30. """Event arguments description."""
  31. def __init__(self, args):
  32. """
  33. Parameters
  34. ----------
  35. args :
  36. List of (type, name) tuples.
  37. """
  38. self._args = args
  39. def copy(self):
  40. """Create a new copy."""
  41. return Arguments(list(self._args))
  42. @staticmethod
  43. def build(arg_str):
  44. """Build and Arguments instance from an argument string.
  45. Parameters
  46. ----------
  47. arg_str : str
  48. String describing the event arguments.
  49. """
  50. res = []
  51. for arg in arg_str.split(","):
  52. arg = arg.strip()
  53. if arg == 'void':
  54. continue
  55. if '*' in arg:
  56. arg_type, identifier = arg.rsplit('*', 1)
  57. arg_type += '*'
  58. identifier = identifier.strip()
  59. else:
  60. arg_type, identifier = arg.rsplit(None, 1)
  61. res.append((arg_type, identifier))
  62. return Arguments(res)
  63. def __iter__(self):
  64. """Iterate over the (type, name) pairs."""
  65. return iter(self._args)
  66. def __len__(self):
  67. """Number of arguments."""
  68. return len(self._args)
  69. def __str__(self):
  70. """String suitable for declaring function arguments."""
  71. if len(self._args) == 0:
  72. return "void"
  73. else:
  74. return ", ".join([ " ".join([t, n]) for t,n in self._args ])
  75. def __repr__(self):
  76. """Evaluable string representation for this object."""
  77. return "Arguments(\"%s\")" % str(self)
  78. def names(self):
  79. """List of argument names."""
  80. return [ name for _, name in self._args ]
  81. def types(self):
  82. """List of argument types."""
  83. return [ type_ for type_, _ in self._args ]
  84. class Event(object):
  85. """Event description.
  86. Attributes
  87. ----------
  88. name : str
  89. The event name.
  90. fmt : str
  91. The event format string.
  92. properties : set(str)
  93. Properties of the event.
  94. args : Arguments
  95. The event arguments.
  96. """
  97. _CRE = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?")
  98. _VALID_PROPS = set(["disable"])
  99. def __init__(self, name, props, fmt, args):
  100. """
  101. Parameters
  102. ----------
  103. name : string
  104. Event name.
  105. props : list of str
  106. Property names.
  107. fmt : str
  108. Event printing format.
  109. args : Arguments
  110. Event arguments.
  111. """
  112. self.name = name
  113. self.properties = props
  114. self.fmt = fmt
  115. self.args = args
  116. unknown_props = set(self.properties) - self._VALID_PROPS
  117. if len(unknown_props) > 0:
  118. raise ValueError("Unknown properties: %s"
  119. % ", ".join(unknown_props))
  120. def copy(self):
  121. """Create a new copy."""
  122. return Event(self.name, list(self.properties), self.fmt,
  123. self.args.copy(), self)
  124. @staticmethod
  125. def build(line_str):
  126. """Build an Event instance from a string.
  127. Parameters
  128. ----------
  129. line_str : str
  130. Line describing the event.
  131. """
  132. m = Event._CRE.match(line_str)
  133. assert m is not None
  134. groups = m.groupdict('')
  135. name = groups["name"]
  136. props = groups["props"].split()
  137. fmt = groups["fmt"]
  138. args = Arguments.build(groups["args"])
  139. return Event(name, props, fmt, args)
  140. def __repr__(self):
  141. """Evaluable string representation for this object."""
  142. return "Event('%s %s(%s) %s')" % (" ".join(self.properties),
  143. self.name,
  144. self.args,
  145. self.fmt)
  146. QEMU_TRACE = "trace_%(name)s"
  147. def api(self, fmt=None):
  148. if fmt is None:
  149. fmt = Event.QEMU_TRACE
  150. return fmt % {"name": self.name}
  151. def _read_events(fobj):
  152. res = []
  153. for line in fobj:
  154. if not line.strip():
  155. continue
  156. if line.lstrip().startswith('#'):
  157. continue
  158. res.append(Event.build(line))
  159. return res
  160. class TracetoolError (Exception):
  161. """Exception for calls to generate."""
  162. pass
  163. def try_import(mod_name, attr_name=None, attr_default=None):
  164. """Try to import a module and get an attribute from it.
  165. Parameters
  166. ----------
  167. mod_name : str
  168. Module name.
  169. attr_name : str, optional
  170. Name of an attribute in the module.
  171. attr_default : optional
  172. Default value if the attribute does not exist in the module.
  173. Returns
  174. -------
  175. A pair indicating whether the module could be imported and the module or
  176. object or attribute value.
  177. """
  178. try:
  179. module = __import__(mod_name, globals(), locals(), ["__package__"])
  180. if attr_name is None:
  181. return True, module
  182. return True, getattr(module, str(attr_name), attr_default)
  183. except ImportError:
  184. return False, None
  185. def generate(fevents, format, backends,
  186. binary=None, probe_prefix=None):
  187. """Generate the output for the given (format, backends) pair.
  188. Parameters
  189. ----------
  190. fevents : file
  191. Event description file.
  192. format : str
  193. Output format name.
  194. backends : list
  195. Output backend names.
  196. binary : str or None
  197. See tracetool.backend.dtrace.BINARY.
  198. probe_prefix : str or None
  199. See tracetool.backend.dtrace.PROBEPREFIX.
  200. """
  201. # fix strange python error (UnboundLocalError tracetool)
  202. import tracetool
  203. format = str(format)
  204. if len(format) is 0:
  205. raise TracetoolError("format not set")
  206. if not tracetool.format.exists(format):
  207. raise TracetoolError("unknown format: %s" % format)
  208. if len(backends) is 0:
  209. raise TracetoolError("no backends specified")
  210. for backend in backends:
  211. if not tracetool.backend.exists(backend):
  212. raise TracetoolError("unknown backend: %s" % backend)
  213. backend = tracetool.backend.Wrapper(backends, format)
  214. import tracetool.backend.dtrace
  215. tracetool.backend.dtrace.BINARY = binary
  216. tracetool.backend.dtrace.PROBEPREFIX = probe_prefix
  217. events = _read_events(fevents)
  218. tracetool.format.generate(events, format, backend)