PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/jit/metainterp/test/support.py

https://bitbucket.org/pypy/pypy/
Python | 331 lines | 243 code | 47 blank | 41 comment | 45 complexity | 7a23edc394133c2053eae16c6849a296 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py, sys
  2. from rpython.rtyper.lltypesystem import lltype, llmemory
  3. from rpython.jit.backend.llgraph import runner
  4. from rpython.jit.metainterp.warmspot import ll_meta_interp, get_stats
  5. from rpython.jit.metainterp.warmspot import reset_stats
  6. from rpython.jit.metainterp.warmstate import unspecialize_value
  7. from rpython.jit.metainterp.optimizeopt import ALL_OPTS_DICT
  8. from rpython.jit.metainterp import pyjitpl, history, jitexc
  9. from rpython.jit.codewriter.policy import JitPolicy
  10. from rpython.jit.codewriter import codewriter, longlong
  11. from rpython.rlib.rfloat import isnan
  12. from rpython.rlib.jit import ENABLE_ALL_OPTS
  13. from rpython.translator.backendopt.all import backend_optimizations
  14. def _get_jitcodes(testself, CPUClass, func, values,
  15. supports_floats=True,
  16. supports_longlong=False,
  17. supports_singlefloats=False,
  18. translationoptions={}, **kwds):
  19. from rpython.jit.codewriter import support
  20. class FakeJitCell(object):
  21. __product_token = None
  22. def get_procedure_token(self):
  23. return self.__product_token
  24. def set_procedure_token(self, token):
  25. self.__product_token = token
  26. class FakeWarmRunnerState(object):
  27. def attach_procedure_to_interp(self, greenkey, procedure_token):
  28. assert greenkey == []
  29. self._cell.set_procedure_token(procedure_token)
  30. def helper_func(self, FUNCPTR, func):
  31. from rpython.rtyper.annlowlevel import llhelper
  32. return llhelper(FUNCPTR, func)
  33. def get_unique_id(self, *args):
  34. return 0
  35. def get_location_str(self, args):
  36. return 'location'
  37. class JitCell:
  38. @staticmethod
  39. def get_jit_cell_at_key(greenkey):
  40. assert greenkey == []
  41. return FakeWarmRunnerState._cell
  42. _cell = FakeJitCell()
  43. trace_limit = sys.maxint
  44. enable_opts = ALL_OPTS_DICT
  45. vec = True
  46. if kwds.pop('disable_optimizations', False):
  47. FakeWarmRunnerState.enable_opts = {}
  48. func._jit_unroll_safe_ = True
  49. rtyper = support.annotate(func, values,
  50. translationoptions=translationoptions)
  51. graphs = rtyper.annotator.translator.graphs
  52. testself.all_graphs = graphs
  53. result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0]
  54. class FakeJitDriver:
  55. name = 'fakejitdriver'
  56. class FakeJitDriverSD:
  57. num_green_args = 0
  58. portal_graph = graphs[0]
  59. virtualizable_info = None
  60. greenfield_info = None
  61. result_type = result_kind
  62. portal_runner_ptr = "???"
  63. vec = False
  64. jitdriver = FakeJitDriver()
  65. stats = history.Stats(None)
  66. cpu = CPUClass(rtyper, stats, None, False)
  67. cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()])
  68. cw.debug = True
  69. testself.cw = cw
  70. if supports_floats and not cpu.supports_floats:
  71. py.test.skip("this test requires supports_floats=True")
  72. if supports_longlong and not cpu.supports_longlong:
  73. py.test.skip("this test requires supports_longlong=True")
  74. if supports_singlefloats and not cpu.supports_singlefloats:
  75. py.test.skip("this test requires supports_singlefloats=True")
  76. policy = JitPolicy()
  77. policy.set_supports_floats(supports_floats)
  78. policy.set_supports_longlong(supports_longlong)
  79. policy.set_supports_singlefloats(supports_singlefloats)
  80. graphs = cw.find_all_graphs(policy)
  81. if kwds.get("backendopt"):
  82. backend_optimizations(rtyper.annotator.translator, graphs=graphs)
  83. #
  84. testself.warmrunnerstate = FakeWarmRunnerState()
  85. testself.warmrunnerstate.cpu = cpu
  86. FakeJitDriverSD.warmstate = testself.warmrunnerstate
  87. if hasattr(testself, 'finish_setup_for_interp_operations'):
  88. testself.finish_setup_for_interp_operations()
  89. #
  90. cw.make_jitcodes(verbose=True)
  91. return stats
  92. def _run_with_blackhole(testself, args):
  93. from rpython.jit.metainterp.blackhole import BlackholeInterpBuilder
  94. cw = testself.cw
  95. blackholeinterpbuilder = BlackholeInterpBuilder(cw)
  96. blackholeinterp = blackholeinterpbuilder.acquire_interp()
  97. count_i = count_r = count_f = 0
  98. for value in args:
  99. T = lltype.typeOf(value)
  100. if T == lltype.Signed:
  101. blackholeinterp.setarg_i(count_i, value)
  102. count_i += 1
  103. elif T == llmemory.GCREF:
  104. blackholeinterp.setarg_r(count_r, value)
  105. count_r += 1
  106. elif T == lltype.Float:
  107. value = longlong.getfloatstorage(value)
  108. blackholeinterp.setarg_f(count_f, value)
  109. count_f += 1
  110. else:
  111. raise TypeError(T)
  112. [jitdriver_sd] = cw.callcontrol.jitdrivers_sd
  113. blackholeinterp.setposition(jitdriver_sd.mainjitcode, 0)
  114. blackholeinterp.run()
  115. return blackholeinterp._final_result_anytype()
  116. def _run_with_pyjitpl(testself, args, stats):
  117. cw = testself.cw
  118. opt = history.Options(listops=True)
  119. metainterp_sd = pyjitpl.MetaInterpStaticData(cw.cpu, opt)
  120. stats.metainterp_sd = metainterp_sd
  121. metainterp_sd.finish_setup(cw)
  122. metainterp_sd.finish_setup_descrs()
  123. [jitdriver_sd] = metainterp_sd.jitdrivers_sd
  124. metainterp = pyjitpl.MetaInterp(metainterp_sd, jitdriver_sd)
  125. testself.metainterp = metainterp
  126. try:
  127. metainterp.compile_and_run_once(jitdriver_sd, *args)
  128. except (jitexc.DoneWithThisFrameInt,
  129. jitexc.DoneWithThisFrameRef,
  130. jitexc.DoneWithThisFrameFloat) as e:
  131. return e.result
  132. else:
  133. raise Exception("FAILED")
  134. def _run_with_machine_code(testself, args):
  135. metainterp = testself.metainterp
  136. num_green_args = metainterp.jitdriver_sd.num_green_args
  137. procedure_token = metainterp.get_procedure_token(args[:num_green_args])
  138. # a loop was successfully created by _run_with_pyjitpl(); call it
  139. cpu = metainterp.cpu
  140. args1 = []
  141. for i in range(len(args) - num_green_args):
  142. x = args[num_green_args + i]
  143. args1.append(unspecialize_value(x))
  144. deadframe = cpu.execute_token(procedure_token, *args1)
  145. faildescr = cpu.get_latest_descr(deadframe)
  146. assert faildescr.__class__.__name__.startswith('DoneWithThisFrameDescr')
  147. if metainterp.jitdriver_sd.result_type == history.INT:
  148. return deadframe, cpu.get_int_value(deadframe, 0)
  149. elif metainterp.jitdriver_sd.result_type == history.REF:
  150. return deadframe, cpu.get_ref_value(deadframe, 0)
  151. elif metainterp.jitdriver_sd.result_type == history.FLOAT:
  152. return deadframe, cpu.get_float_value(deadframe, 0)
  153. else:
  154. return deadframe, None
  155. class JitMixin:
  156. basic = True
  157. enable_opts = ENABLE_ALL_OPTS
  158. # Basic terminology: the JIT produces "loops" and "bridges".
  159. # Bridges are always attached to failing guards. Every loop is
  160. # the "trunk" of a tree of compiled code, which is formed by first
  161. # compiling a loop and then incrementally adding some number of
  162. # bridges to it. Each loop and each bridge ends with either a
  163. # FINISH or a JUMP instruction (the name "loop" is not really
  164. # adapted any more). The JUMP instruction jumps to any LABEL
  165. # pseudo-instruction, which can be anywhere, within the same tree
  166. # or another one.
  167. def check_resops(self, expected=None, **check):
  168. """Check the instructions in all loops and bridges, ignoring
  169. the ones that end in FINISH. Either pass a dictionary (then
  170. the check must match exactly), or some keyword arguments (then
  171. the check is only about the instructions named)."""
  172. if self.enable_opts == ENABLE_ALL_OPTS:
  173. get_stats().check_resops(expected=expected, **check)
  174. def check_simple_loop(self, expected=None, **check):
  175. """Useful in the simplest case when we have only one loop
  176. ending with a jump back to itself and possibly a few bridges.
  177. Only the operations within the loop formed by that single jump
  178. will be counted; the bridges are all ignored. If several loops
  179. were compiled, complains."""
  180. if self.enable_opts == ENABLE_ALL_OPTS:
  181. get_stats().check_simple_loop(expected=expected, **check)
  182. def check_trace_count(self, count): # was check_loop_count
  183. """Check the number of loops and bridges compiled."""
  184. if self.enable_opts == ENABLE_ALL_OPTS:
  185. assert get_stats().compiled_count == count
  186. def check_trace_count_at_most(self, count):
  187. """Check the number of loops and bridges compiled."""
  188. if self.enable_opts == ENABLE_ALL_OPTS:
  189. assert get_stats().compiled_count <= count
  190. def check_jitcell_token_count(self, count): # was check_tree_loop_count
  191. """This should check the number of independent trees of code.
  192. (xxx it is not 100% clear that the count is correct)"""
  193. if self.enable_opts == ENABLE_ALL_OPTS:
  194. assert len(get_stats().jitcell_token_wrefs) == count
  195. def check_target_token_count(self, count):
  196. """(xxx unknown)"""
  197. if self.enable_opts == ENABLE_ALL_OPTS:
  198. tokens = get_stats().get_all_jitcell_tokens()
  199. n = sum([len(t.target_tokens) for t in tokens])
  200. assert n == count
  201. def check_enter_count(self, count):
  202. """Check the number of times pyjitpl ran. (Every time, it
  203. should have produced either one loop or one bridge, or aborted;
  204. but it is not 100% clear that this is still correct in the
  205. presence of unrolling.)"""
  206. if self.enable_opts == ENABLE_ALL_OPTS:
  207. assert get_stats().enter_count == count
  208. def check_enter_count_at_most(self, count):
  209. """Check the number of times pyjitpl ran."""
  210. if self.enable_opts == ENABLE_ALL_OPTS:
  211. assert get_stats().enter_count <= count
  212. def check_aborted_count(self, count):
  213. """Check the number of times pyjitpl was aborted."""
  214. if self.enable_opts == ENABLE_ALL_OPTS:
  215. assert get_stats().aborted_count == count
  216. def check_aborted_count_at_least(self, count):
  217. """Check the number of times pyjitpl was aborted."""
  218. if self.enable_opts == ENABLE_ALL_OPTS:
  219. assert get_stats().aborted_count >= count
  220. def meta_interp(self, *args, **kwds):
  221. kwds['CPUClass'] = self.CPUClass
  222. if "backendopt" not in kwds:
  223. kwds["backendopt"] = False
  224. if "enable_opts" not in kwds and hasattr(self, 'enable_opts'):
  225. kwds['enable_opts'] = self.enable_opts
  226. old = codewriter.CodeWriter.debug
  227. try:
  228. codewriter.CodeWriter.debug = True
  229. return ll_meta_interp(*args, **kwds)
  230. finally:
  231. codewriter.CodeWriter.debug = old
  232. def interp_operations(self, f, args, **kwds):
  233. # get the JitCodes for the function f
  234. stats = _get_jitcodes(self, self.CPUClass, f, args, **kwds)
  235. # try to run it with blackhole.py
  236. result1 = _run_with_blackhole(self, args)
  237. # try to run it with pyjitpl.py
  238. result2 = _run_with_pyjitpl(self, args, stats)
  239. assert result1 == result2 or isnan(result1) and isnan(result2)
  240. # try to run it by running the code compiled just before
  241. df, result3 = _run_with_machine_code(self, args)
  242. self._lastframe = df
  243. assert result1 == result3 or result3 == NotImplemented or isnan(result1) and isnan(result3)
  244. #
  245. if (longlong.supports_longlong and
  246. isinstance(result1, longlong.r_float_storage)):
  247. result1 = longlong.getrealfloat(result1)
  248. return result1
  249. def check_history(self, expected=None, **isns):
  250. # this can be used after calling meta_interp
  251. get_stats().check_history(expected, **isns)
  252. def check_operations_history(self, expected=None, **isns):
  253. # this can be used after interp_operations
  254. if expected is not None:
  255. expected = dict(expected)
  256. expected['finish'] = 1
  257. self.metainterp.staticdata.stats.check_history(expected, **isns)
  258. class LLJitMixin(JitMixin):
  259. CPUClass = runner.LLGraphCPU
  260. @staticmethod
  261. def Ptr(T):
  262. return lltype.Ptr(T)
  263. @staticmethod
  264. def GcStruct(name, *fields, **kwds):
  265. S = lltype.GcStruct(name, *fields, **kwds)
  266. return S
  267. malloc = staticmethod(lltype.malloc)
  268. nullptr = staticmethod(lltype.nullptr)
  269. @staticmethod
  270. def malloc_immortal(T):
  271. return lltype.malloc(T, immortal=True)
  272. def _get_NODE(self):
  273. NODE = lltype.GcForwardReference()
  274. NODE.become(lltype.GcStruct('NODE', ('value', lltype.Signed),
  275. ('next', lltype.Ptr(NODE))))
  276. return NODE
  277. # ____________________________________________________________
  278. class _Foo:
  279. pass
  280. def noConst(x):
  281. """Helper function for tests, returning 'x' as a BoxInt/BoxPtr
  282. even if it is a ConstInt/ConstPtr."""
  283. from rpython.rlib import jit
  284. return jit.hint(x, force_no_const=True)