PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/jit/metainterp/test/test_warmspot.py

https://bitbucket.org/pypy/pypy/
Python | 381 lines | 363 code | 17 blank | 1 comment | 14 complexity | 3812c5b9b60a3dbf9d86670842e728fe MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. from pypy.jit.metainterp.warmspot import get_stats
  3. from pypy.rlib.jit import JitDriver, set_param, unroll_safe
  4. from pypy.jit.backend.llgraph import runner
  5. from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
  6. from pypy.jit.metainterp.optimizeopt import ALL_OPTS_NAMES
  7. class Exit(Exception):
  8. def __init__(self, result):
  9. self.result = result
  10. class WarmspotTests(object):
  11. def test_basic(self):
  12. mydriver = JitDriver(reds=['a'],
  13. greens=['i'])
  14. CODE_INCREASE = 0
  15. CODE_JUMP = 1
  16. lst = [CODE_INCREASE, CODE_INCREASE, CODE_JUMP]
  17. def interpreter_loop(a):
  18. i = 0
  19. while True:
  20. mydriver.jit_merge_point(i=i, a=a)
  21. if i >= len(lst):
  22. break
  23. elem = lst[i]
  24. if elem == CODE_INCREASE:
  25. a = a + 1
  26. i += 1
  27. elif elem == CODE_JUMP:
  28. if a < 20:
  29. i = 0
  30. mydriver.can_enter_jit(i=i, a=a)
  31. else:
  32. i += 1
  33. else:
  34. pass
  35. raise Exit(a)
  36. def main(a):
  37. try:
  38. interpreter_loop(a)
  39. except Exit, e:
  40. return e.result
  41. res = self.meta_interp(main, [1])
  42. assert res == 21
  43. def test_reentry(self):
  44. mydriver = JitDriver(reds = ['n'], greens = [])
  45. def f(n):
  46. while n > 0:
  47. mydriver.can_enter_jit(n=n)
  48. mydriver.jit_merge_point(n=n)
  49. if n % 20 == 0:
  50. n -= 2
  51. n -= 1
  52. res = self.meta_interp(f, [60])
  53. assert res == f(30)
  54. def test_location(self):
  55. def get_printable_location(n):
  56. return 'GREEN IS %d.' % n
  57. myjitdriver = JitDriver(greens=['n'], reds=['m'],
  58. get_printable_location=get_printable_location)
  59. def f(n, m):
  60. while m > 0:
  61. myjitdriver.can_enter_jit(n=n, m=m)
  62. myjitdriver.jit_merge_point(n=n, m=m)
  63. m -= 1
  64. self.meta_interp(f, [123, 10])
  65. assert len(get_stats().locations) >= 4
  66. for loc in get_stats().locations:
  67. assert loc == (0, 123)
  68. def test_set_param_enable_opts(self):
  69. from pypy.rpython.annlowlevel import llstr, hlstr
  70. myjitdriver = JitDriver(greens = [], reds = ['n'])
  71. class A(object):
  72. def m(self, n):
  73. return n-1
  74. def g(n):
  75. while n > 0:
  76. myjitdriver.can_enter_jit(n=n)
  77. myjitdriver.jit_merge_point(n=n)
  78. n = A().m(n)
  79. return n
  80. def f(n, enable_opts):
  81. set_param(None, 'enable_opts', hlstr(enable_opts))
  82. return g(n)
  83. # check that the set_param will override the default
  84. res = self.meta_interp(f, [10, llstr('')])
  85. assert res == 0
  86. self.check_resops(new_with_vtable=1)
  87. res = self.meta_interp(f, [10, llstr(ALL_OPTS_NAMES)],
  88. enable_opts='')
  89. assert res == 0
  90. self.check_resops(new_with_vtable=0)
  91. def test_unwanted_loops(self):
  92. mydriver = JitDriver(reds = ['n', 'total', 'm'], greens = [])
  93. def loop1(n):
  94. # the jit should not look here, as there is a loop
  95. res = 0
  96. for i in range(n):
  97. res += i
  98. return res
  99. @unroll_safe
  100. def loop2(n):
  101. # the jit looks here, due to the decorator
  102. for i in range(5):
  103. n += 1
  104. return n
  105. def f(m):
  106. total = 0
  107. n = 0
  108. while n < m:
  109. mydriver.can_enter_jit(n=n, total=total, m=m)
  110. mydriver.jit_merge_point(n=n, total=total, m=m)
  111. total += loop1(n)
  112. n = loop2(n)
  113. return total
  114. self.meta_interp(f, [50])
  115. self.check_enter_count_at_most(2)
  116. def test_wanted_unrolling_and_preinlining(self):
  117. mydriver = JitDriver(reds = ['n', 'm'], greens = [])
  118. @unroll_safe
  119. def loop2(n):
  120. # the jit looks here, due to the decorator
  121. for i in range(5):
  122. n += 1
  123. return n
  124. loop2._always_inline_ = True
  125. def g(n):
  126. return loop2(n)
  127. g._dont_inline_ = True
  128. def f(m):
  129. n = 0
  130. while n < m:
  131. mydriver.can_enter_jit(n=n, m=m)
  132. mydriver.jit_merge_point(n=n, m=m)
  133. n = g(n)
  134. return n
  135. self.meta_interp(f, [50], backendopt=True)
  136. self.check_enter_count_at_most(2)
  137. self.check_resops(call=0)
  138. def test_loop_header(self):
  139. # artificial test: we enter into the JIT only when can_enter_jit()
  140. # is seen, but we close a loop in the JIT much more quickly
  141. # because of loop_header().
  142. mydriver = JitDriver(reds = ['n', 'm'], greens = [])
  143. def f(m):
  144. n = 0
  145. while True:
  146. mydriver.jit_merge_point(n=n, m=m)
  147. if n > m:
  148. m -= 1
  149. if m < 0:
  150. return n
  151. n = 0
  152. mydriver.can_enter_jit(n=n, m=m)
  153. else:
  154. n += 1
  155. mydriver.loop_header()
  156. assert f(15) == 1
  157. res = self.meta_interp(f, [15], backendopt=True)
  158. assert res == 1
  159. self.check_resops(int_add=2) # I get 13 without the loop_header()
  160. def test_omit_can_enter_jit(self):
  161. # Simple test comparing the effects of always giving a can_enter_jit(),
  162. # or not giving any. Mostly equivalent, except that if given, it is
  163. # ignored the first time, and so it ends up taking one extra loop to
  164. # start JITting.
  165. mydriver = JitDriver(greens=[], reds=['m'])
  166. #
  167. for i2 in range(10):
  168. def f2(m):
  169. while m > 0:
  170. mydriver.jit_merge_point(m=m)
  171. m -= 1
  172. self.meta_interp(f2, [i2])
  173. try:
  174. self.check_jitcell_token_count(1)
  175. break
  176. except AssertionError:
  177. print "f2: no loop generated for i2==%d" % i2
  178. else:
  179. raise # re-raise the AssertionError: check_loop_count never 1
  180. #
  181. for i1 in range(10):
  182. def f1(m):
  183. while m > 0:
  184. mydriver.can_enter_jit(m=m)
  185. mydriver.jit_merge_point(m=m)
  186. m -= 1
  187. self.meta_interp(f1, [i1])
  188. try:
  189. self.check_jitcell_token_count(1)
  190. break
  191. except AssertionError:
  192. print "f1: no loop generated for i1==%d" % i1
  193. else:
  194. raise # re-raise the AssertionError: check_loop_count never 1
  195. #
  196. assert i1 - 1 == i2
  197. def test_no_loop_at_all(self):
  198. mydriver = JitDriver(greens=[], reds=['m'])
  199. def f2(m):
  200. mydriver.jit_merge_point(m=m)
  201. return m - 1
  202. def f1(m):
  203. while m > 0:
  204. m = f2(m)
  205. self.meta_interp(f1, [8])
  206. # it should generate one "loop" only, which ends in a FINISH
  207. # corresponding to the return from f2.
  208. self.check_trace_count(1)
  209. self.check_resops(jump=0)
  210. def test_simple_loop(self):
  211. mydriver = JitDriver(greens=[], reds=['m'])
  212. def f1(m):
  213. while m > 0:
  214. mydriver.jit_merge_point(m=m)
  215. m = m - 1
  216. self.meta_interp(f1, [8])
  217. self.check_trace_count(1)
  218. self.check_resops({'jump': 1, 'guard_true': 2, 'int_gt': 2,
  219. 'int_sub': 2})
  220. def test_void_red_variable(self):
  221. mydriver = JitDriver(greens=[], reds=['a', 'm'])
  222. def f1(m):
  223. a = None
  224. while m > 0:
  225. mydriver.jit_merge_point(a=a, m=m)
  226. m = m - 1
  227. if m == 10:
  228. pass # other case
  229. self.meta_interp(f1, [18])
  230. def test_bug_constant_rawptrs(self):
  231. py.test.skip("crashes because a is a constant")
  232. from pypy.rpython.lltypesystem import lltype, rffi
  233. mydriver = JitDriver(greens=['a'], reds=['m'])
  234. def f1(m):
  235. a = lltype.nullptr(rffi.VOIDP.TO)
  236. while m > 0:
  237. mydriver.jit_merge_point(a=a, m=m)
  238. m = m - 1
  239. self.meta_interp(f1, [18])
  240. def test_bug_rawptrs(self):
  241. from pypy.rpython.lltypesystem import lltype, rffi
  242. mydriver = JitDriver(greens=['a'], reds=['m'])
  243. def f1(m):
  244. a = lltype.malloc(rffi.VOIDP.TO, 5, flavor='raw')
  245. while m > 0:
  246. mydriver.jit_merge_point(a=a, m=m)
  247. m = m - 1
  248. if m == 10:
  249. pass
  250. lltype.free(a, flavor='raw')
  251. self.meta_interp(f1, [18])
  252. class TestLLWarmspot(WarmspotTests, LLJitMixin):
  253. CPUClass = runner.LLtypeCPU
  254. type_system = 'lltype'
  255. class TestOOWarmspot(WarmspotTests, OOJitMixin):
  256. ##CPUClass = runner.OOtypeCPU
  257. type_system = 'ootype'
  258. class TestWarmspotDirect(object):
  259. def setup_class(cls):
  260. from pypy.jit.metainterp.typesystem import llhelper
  261. from pypy.jit.codewriter.support import annotate
  262. from pypy.jit.metainterp.warmspot import WarmRunnerDesc
  263. from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
  264. from pypy.rpython.lltypesystem import lltype, llmemory
  265. exc_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
  266. cls.exc_vtable = exc_vtable
  267. class FakeFailDescr(object):
  268. def __init__(self, no):
  269. self.no = no
  270. def handle_fail(self, metainterp_sd, jitdrivers_sd):
  271. no = self.no
  272. if no == 0:
  273. raise metainterp_sd.warmrunnerdesc.DoneWithThisFrameInt(3)
  274. if no == 1:
  275. raise metainterp_sd.warmrunnerdesc.ContinueRunningNormally(
  276. [0], [], [], [1], [], [])
  277. if no == 3:
  278. exc = lltype.malloc(OBJECT)
  279. exc.typeptr = exc_vtable
  280. raise metainterp_sd.warmrunnerdesc.ExitFrameWithExceptionRef(
  281. metainterp_sd.cpu,
  282. lltype.cast_opaque_ptr(llmemory.GCREF, exc))
  283. assert 0
  284. class FakeDescr:
  285. def as_vtable_size_descr(self):
  286. return self
  287. class FakeCPU(object):
  288. supports_floats = False
  289. supports_longlong = False
  290. supports_singlefloats = False
  291. ts = llhelper
  292. translate_support_code = False
  293. stats = "stats"
  294. def get_fail_descr_number(self, d):
  295. return -1
  296. def __init__(self, *args, **kwds):
  297. pass
  298. def nodescr(self, *args, **kwds):
  299. return FakeDescr()
  300. fielddescrof = nodescr
  301. calldescrof = nodescr
  302. sizeof = nodescr
  303. def get_fail_descr_from_number(self, no):
  304. return FakeFailDescr(no)
  305. def make_execute_token(self, *ARGS):
  306. return "not callable"
  307. driver = JitDriver(reds = ['red'], greens = ['green'])
  308. def f(green):
  309. red = 0
  310. while red < 10:
  311. driver.can_enter_jit(red=red, green=green)
  312. driver.jit_merge_point(red=red, green=green)
  313. red += 1
  314. return red
  315. rtyper = annotate(f, [0])
  316. FakeCPU.rtyper = rtyper
  317. translator = rtyper.annotator.translator
  318. translator.config.translation.gc = 'hybrid'
  319. cls.desc = WarmRunnerDesc(translator, CPUClass=FakeCPU)
  320. def test_call_helper(self):
  321. from pypy.rpython.llinterp import LLException
  322. [jd] = self.desc.jitdrivers_sd
  323. assert jd._assembler_call_helper(0, 0) == 3
  324. assert jd._assembler_call_helper(1, 0) == 10
  325. try:
  326. jd._assembler_call_helper(3, 0)
  327. except LLException, lle:
  328. assert lle[0] == self.exc_vtable
  329. else:
  330. py.test.fail("DID NOT RAISE")