[pypy-svn] r67604 - in pypy/trunk/pypy: jit/metainterp jit/metainterp/test rlib translator
cfbolz at codespeak.net
cfbolz at codespeak.net
Thu Sep 10 12:12:41 CEST 2009
Author: cfbolz
Date: Thu Sep 10 12:12:41 2009
New Revision: 67604
Modified:
pypy/trunk/pypy/jit/metainterp/history.py
pypy/trunk/pypy/jit/metainterp/pyjitpl.py
pypy/trunk/pypy/jit/metainterp/test/test_basic.py
pypy/trunk/pypy/jit/metainterp/test/test_recursive.py
pypy/trunk/pypy/jit/metainterp/warmspot.py
pypy/trunk/pypy/rlib/jit.py
pypy/trunk/pypy/translator/driver.py
Log:
merge agressive-inlining branch
Modified: pypy/trunk/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/history.py (original)
+++ pypy/trunk/pypy/jit/metainterp/history.py Thu Sep 10 12:12:41 2009
@@ -788,6 +788,7 @@
compiled_count = 0
enter_count = 0
+ aborted_count = 0
def __init__(self):
self.loops = []
@@ -853,10 +854,9 @@
class Options:
logger_noopt = None
- def __init__(self, specialize=True, listops=False, inline=False):
+ def __init__(self, specialize=True, listops=False):
self.specialize = specialize
self.listops = listops
- self.inline = inline
def _freeze_(self):
return True
Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original)
+++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Thu Sep 10 12:12:41 2009
@@ -645,12 +645,12 @@
@arguments("descr", "varargs")
def opimpl_recursive_call(self, calldescr, varargs):
- if self.metainterp.staticdata.options.inline:
+ warmrunnerstate = self.metainterp.staticdata.state
+ if warmrunnerstate.inlining:
num_green_args = self.metainterp.staticdata.num_green_args
portal_code = self.metainterp.staticdata.portal_code
greenkey = varargs[1:num_green_args + 1]
if self.metainterp.staticdata.state.can_inline_callable(greenkey):
- self.metainterp.in_recursion += 1
return self.perform_call(portal_code, varargs[1:])
return self.execute_with_exc(rop.CALL, varargs, descr=calldescr)
@@ -1128,14 +1128,20 @@
def newframe(self, jitcode):
if not we_are_translated():
self._debug_history.append(['enter', jitcode, None])
+ if jitcode is self.staticdata.portal_code:
+ self.in_recursion += 1
f = MIFrame(self, jitcode)
self.framestack.append(f)
return f
- def finishframe(self, resultbox):
+ def popframe(self):
frame = self.framestack.pop()
if frame.jitcode is self.staticdata.portal_code:
self.in_recursion -= 1
+ return frame
+
+ def finishframe(self, resultbox):
+ frame = self.popframe()
if not we_are_translated():
self._debug_history.append(['leave', frame.jitcode, None])
if self.framestack:
@@ -1178,11 +1184,29 @@
return True
if not we_are_translated():
self._debug_history.append(['leave_exc', frame.jitcode, None])
- self.framestack.pop()
+ self.popframe()
if not self.is_blackholing():
self.compile_exit_frame_with_exception(excvaluebox)
raise self.staticdata.ExitFrameWithExceptionRef(self.cpu, excvaluebox.getref_base())
+ def check_recursion_invariant(self):
+ in_recursion = -1
+ for frame in self.framestack:
+ jitcode = frame.jitcode
+ if jitcode is self.staticdata.portal_code:
+ in_recursion += 1
+ if in_recursion != self.in_recursion:
+ print "in_recursion problem!!!"
+ print in_recursion, self.in_recursion
+ for frame in self.framestack:
+ jitcode = frame.jitcode
+ if jitcode is self.staticdata.portal_code:
+ print "P",
+ else:
+ print " ",
+ print jitcode.name
+ raise Exception
+
def raise_overflow_error(self):
etype, evalue = self.cpu.get_overflow_error()
return self.finishframe_exception(
@@ -1196,6 +1220,7 @@
self.cpu.ts.get_exc_value_box(evalue))
def create_empty_history(self):
+ warmrunnerstate = self.staticdata.state
self.history = history.History(self.cpu)
if self.staticdata.stats is not None:
self.staticdata.stats.history = self.history
@@ -1245,6 +1270,19 @@
op.pc = self.framestack[-1].pc
op.name = self.framestack[-1].jitcode.name
+ def switch_to_blackhole_if_trace_too_long(self):
+ if not self.is_blackholing():
+ warmrunnerstate = self.staticdata.state
+ if len(self.history.operations) > warmrunnerstate.trace_limit:
+ self.history = history.BlackHole(self.cpu)
+ if not we_are_translated():
+ self.staticdata.stats.aborted_count += 1
+ history.log.event('ABORTING TRACING' + self.history.extratext)
+ elif DEBUG:
+ debug_print('~~~ ABORTING TRACING', self.history.extratext)
+ self.staticdata.profiler.end_tracing()
+ self.staticdata.profiler.start_blackhole()
+
def _interpret(self):
# Execute the frames forward until we raise a DoneWithThisFrame,
# a ContinueRunningNormally, or a GenerateMergePoint exception.
@@ -1256,6 +1294,9 @@
try:
while True:
self.framestack[-1].run_one_step()
+ self.switch_to_blackhole_if_trace_too_long()
+ if not we_are_translated():
+ self.check_recursion_invariant()
finally:
if self.is_blackholing():
self.staticdata.profiler.end_blackhole()
@@ -1292,7 +1333,8 @@
return self.designate_target_loop(gmp)
def handle_guard_failure(self, exec_result, key):
- self.initialize_state_from_guard_failure(exec_result)
+ from pypy.jit.metainterp.warmspot import ContinueRunningNormallyBase
+ resumedescr = self.initialize_state_from_guard_failure(exec_result)
assert isinstance(key, compile.ResumeGuardDescr)
top_history = key.find_toplevel_history()
source_loop = top_history.source_link
@@ -1302,12 +1344,18 @@
self.resumekey = key
self.seen_can_enter_jit = False
guard_op = key.get_guard_op()
+ started_as_blackhole = self.is_blackholing()
try:
self.prepare_resume_from_failure(guard_op.opnum)
self.interpret()
assert False, "should always raise"
except GenerateMergePoint, gmp:
return self.designate_target_loop(gmp)
+ except ContinueRunningNormallyBase:
+ if not started_as_blackhole:
+ warmrunnerstate = self.staticdata.state
+ warmrunnerstate.reset_counter_from_failure(resumedescr)
+ raise
def forget_consts(self, boxes, startindex=0):
for i in range(startindex, len(boxes)):
@@ -1499,7 +1547,7 @@
*args[1:])
def initialize_state_from_start(self, *args):
- self.in_recursion = 0
+ self.in_recursion = -1 # always one portal around
self.staticdata._setup_once()
self.staticdata.profiler.start_tracing()
self.create_empty_history()
@@ -1516,7 +1564,7 @@
def initialize_state_from_guard_failure(self, guard_failure):
# guard failure: rebuild a complete MIFrame stack
- self.in_recursion = 0
+ self.in_recursion = -1 # always one portal around
resumedescr = guard_failure.descr
assert isinstance(resumedescr, compile.ResumeGuardDescr)
warmrunnerstate = self.staticdata.state
@@ -1542,6 +1590,7 @@
# the BlackHole is invalid because it doesn't start with
# guard_failure.key.guard_op.suboperations, but that's fine
self.rebuild_state_after_failure(resumedescr, guard_failure.args)
+ return resumedescr
def initialize_virtualizable(self, original_boxes):
vinfo = self.staticdata.virtualizable_info
@@ -1642,10 +1691,7 @@
jitcode, pc, exception_target = resumereader.consume_frame_info()
env = resumereader.consume_boxes()
f = self.newframe(jitcode)
- if jitcode is self.staticdata.portal_code:
- self.in_recursion += 1
f.setup_resume_at_op(pc, exception_target, env)
- self.in_recursion -= 1 # always one portal around
def check_synchronized_virtualizable(self):
if not we_are_translated():
Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Thu Sep 10 12:12:41 2009
@@ -1,4 +1,5 @@
import py
+import sys
from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside
from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
from pypy.jit.backend.llgraph import runner
@@ -49,6 +50,8 @@
assert get_stats().enter_count <= count
def check_jumps(self, maxcount):
assert get_stats().exec_jumps <= maxcount
+ def check_aborted_count(self, maxcount):
+ assert get_stats().aborted_count == maxcount
def meta_interp(self, *args, **kwds):
kwds['CPUClass'] = self.CPUClass
@@ -70,6 +73,8 @@
class FakeWarmRunnerDesc:
def attach_unoptimized_bridge_from_interp(self, greenkey, newloop):
pass
+
+ trace_limit = sys.maxint
if policy is None:
policy = JitPolicy()
Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Thu Sep 10 12:12:41 2009
@@ -4,7 +4,7 @@
from pypy.jit.metainterp import simple_optimize
from pypy.jit.metainterp.policy import StopAtXPolicy
from pypy.rpython.annlowlevel import hlstr
-from pypy.jit.metainterp.warmspot import CannotInlineCanEnterJit
+from pypy.jit.metainterp.warmspot import CannotInlineCanEnterJit, get_stats
class RecursiveTests:
@@ -213,6 +213,170 @@
res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True)
assert res == 0
+ def test_exception_in_inlined_function(self):
+ from pypy.rpython.annlowlevel import hlstr
+ def p(code, pc):
+ code = hlstr(code)
+ return "%s %d %s" % (code, pc, code[pc])
+ def c(code, pc):
+ return "l" not in hlstr(code)
+ myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'],
+ get_printable_location=p, can_inline=c)
+
+ class Exc(Exception):
+ pass
+
+ def f(code, n):
+ pc = 0
+ while pc < len(code):
+
+ myjitdriver.jit_merge_point(n=n, code=code, pc=pc)
+ op = code[pc]
+ if op == "-":
+ n -= 1
+ elif op == "c":
+ try:
+ n = f("---i---", n)
+ except Exc:
+ pass
+ elif op == "i":
+ if n % 5 == 1:
+ raise Exc
+ elif op == "l":
+ if n > 0:
+ myjitdriver.can_enter_jit(n=n, code=code, pc=0)
+ pc = 0
+ continue
+ else:
+ assert 0
+ pc += 1
+ return n
+ def main(n):
+ return f("c-l", n)
+ res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True)
+ assert res == main(100)
+
+ def test_recurse_during_blackholing(self):
+ # this passes, if the blackholing shortcut for calls is turned off
+ # it fails, it is very delicate in terms of parameters,
+ # bridge/loop creation order
+ from pypy.rpython.annlowlevel import hlstr
+ def p(code, pc):
+ code = hlstr(code)
+ return "%s %d %s" % (code, pc, code[pc])
+ def c(code, pc):
+ return "l" not in hlstr(code)
+ myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'],
+ get_printable_location=p, can_inline=c)
+
+ def f(code, n):
+ pc = 0
+ while pc < len(code):
+
+ myjitdriver.jit_merge_point(n=n, code=code, pc=pc)
+ op = code[pc]
+ if op == "-":
+ n -= 1
+ elif op == "c":
+ if n < 70 and n % 3 == 1:
+ print "F"
+ n = f("--", n)
+ elif op == "l":
+ if n > 0:
+ myjitdriver.can_enter_jit(n=n, code=code, pc=0)
+ pc = 0
+ continue
+ else:
+ assert 0
+ pc += 1
+ return n
+ def main(n):
+ myjitdriver.set_param('threshold', 3)
+ myjitdriver.set_param('trace_eagerness', 5)
+ return f("c-l", n)
+ expected = main(100)
+ res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True)
+ assert res == expected
+
+ def check_max_trace_length(self, length):
+ for loop in get_stats().loops:
+ assert len(loop.operations) <= length + 5 # because we only check once per metainterp bytecode
+ for op in loop.operations:
+ if op.is_guard():
+ assert len(op.suboperations) <= length + 5
+
+ def test_inline_trace_limit(self):
+ myjitdriver = JitDriver(greens=[], reds=['n'])
+ def recursive(n):
+ if n > 0:
+ return recursive(n - 1) + 1
+ return 0
+ def loop(n):
+ myjitdriver.set_param("threshold", 10)
+ pc = 0
+ while n:
+ myjitdriver.can_enter_jit(n=n)
+ myjitdriver.jit_merge_point(n=n)
+ n = recursive(n)
+ n -= 1
+ return n
+ TRACE_LIMIT = 66
+ res = self.meta_interp(loop, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT)
+ assert res == 0
+ self.check_max_trace_length(TRACE_LIMIT)
+ self.check_enter_count(15) # maybe
+ self.check_aborted_count(7)
+
+ def test_trace_limit_bridge(self):
+ def recursive(n):
+ if n > 0:
+ return recursive(n - 1) + 1
+ return 0
+ myjitdriver = JitDriver(greens=[], reds=['n'])
+ def loop(n):
+ myjitdriver.set_param("threshold", 4)
+ myjitdriver.set_param("trace_eagerness", 2)
+ while n:
+ myjitdriver.can_enter_jit(n=n)
+ myjitdriver.jit_merge_point(n=n)
+ if n % 5 == 0:
+ n -= 1
+ if n < 50:
+ n = recursive(n)
+ n -= 1
+ TRACE_LIMIT = 20
+ res = self.meta_interp(loop, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT)
+ self.check_max_trace_length(TRACE_LIMIT)
+ self.check_aborted_count(8)
+ self.check_enter_count_at_most(30)
+
+ def test_set_param_inlining(self):
+ myjitdriver = JitDriver(greens=[], reds=['n', 'recurse'])
+ def loop(n, recurse=False):
+ while n:
+ myjitdriver.jit_merge_point(n=n, recurse=recurse)
+ n -= 1
+ if not recurse:
+ loop(10, True)
+ myjitdriver.can_enter_jit(n=n, recurse=recurse)
+ return n
+ TRACE_LIMIT = 66
+
+ def main(inline):
+ myjitdriver.set_param("threshold", 10)
+ if inline:
+ myjitdriver.set_param('inlining', True)
+ else:
+ myjitdriver.set_param('inlining', False)
+ return loop(100)
+
+ res = self.meta_interp(main, [0], optimizer=simple_optimize, trace_limit=TRACE_LIMIT)
+ self.check_loops(call=1)
+
+ res = self.meta_interp(main, [1], optimizer=simple_optimize, trace_limit=TRACE_LIMIT)
+ self.check_loops(call=0)
+
+
class TestLLtype(RecursiveTests, LLJitMixin):
pass
Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/warmspot.py (original)
+++ pypy/trunk/pypy/jit/metainterp/warmspot.py Thu Sep 10 12:12:41 2009
@@ -26,7 +26,9 @@
# ____________________________________________________________
# Bootstrapping
-def apply_jit(translator, backend_name="auto", debug_level="steps", **kwds):
+def apply_jit(translator, backend_name="auto", debug_level="steps",
+ inline=False,
+ **kwds):
if 'CPUClass' not in kwds:
from pypy.jit.backend.detect_cpu import getcpuclass
kwds['CPUClass'] = getcpuclass(backend_name)
@@ -38,9 +40,9 @@
warmrunnerdesc = WarmRunnerDesc(translator,
translate_support_code=True,
listops=True,
- #inline=True,
profile=profile,
**kwds)
+ warmrunnerdesc.state.set_param_inlining(inline)
warmrunnerdesc.finish()
translator.warmrunnerdesc = warmrunnerdesc # for later debugging
@@ -52,13 +54,15 @@
clear_tcache()
return jittify_and_run(interp, graph, args, backendopt=backendopt, **kwds)
-def jittify_and_run(interp, graph, args, repeat=1, hash_bits=None, backendopt=False,
- **kwds):
+def jittify_and_run(interp, graph, args, repeat=1, hash_bits=None, backendopt=False, trace_limit=sys.maxint,
+ inline=False, **kwds):
translator = interp.typer.annotator.translator
translator.config.translation.gc = "boehm"
warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds)
warmrunnerdesc.state.set_param_threshold(3) # for tests
warmrunnerdesc.state.set_param_trace_eagerness(2) # for tests
+ warmrunnerdesc.state.set_param_trace_limit(trace_limit)
+ warmrunnerdesc.state.set_param_inlining(inline)
warmrunnerdesc.state.create_tables_now() # for tests
if hash_bits:
warmrunnerdesc.state.set_param_hash_bits(hash_bits)
@@ -120,6 +124,9 @@
class JitException(Exception):
_go_through_llinterp_uncaught_ = True # ugh
+class ContinueRunningNormallyBase(JitException):
+ pass
+
class CannotInlineCanEnterJit(JitException):
pass
@@ -409,7 +416,7 @@
def __str__(self):
return 'ExitFrameWithExceptionRef(%s)' % (self.value,)
- class ContinueRunningNormally(JitException):
+ class ContinueRunningNormally(ContinueRunningNormallyBase):
def __init__(self, argboxes):
# accepts boxes as argument, but unpacks them immediately
# before we raise the exception -- the boxes' values will
@@ -728,6 +735,12 @@
def set_param_trace_eagerness(self, value):
self.trace_eagerness = value
+ def set_param_trace_limit(self, value):
+ self.trace_limit = value
+
+ def set_param_inlining(self, value):
+ self.inlining = value
+
def set_param_hash_bits(self, value):
if value < 1:
value = 1
@@ -772,7 +785,13 @@
self.create_tables_now()
return
metainterp = MetaInterp(metainterp_sd)
- loop = metainterp.compile_and_run_once(*args)
+ try:
+ loop = metainterp.compile_and_run_once(*args)
+ except warmrunnerdesc.ContinueRunningNormally:
+ # the trace got too long, reset the counter
+ self.mccounters[argshash] = 0
+ raise
+
else:
# machine code was already compiled for these greenargs
# (or we have a hash collision)
@@ -861,6 +880,9 @@
key.counter += 1
return key.counter >= self.trace_eagerness
+ def reset_counter_from_failure(self, key):
+ key.counter = 0
+
def attach_unoptimized_bridge_from_interp(self, greenkey, bridge):
greenargs = self.unwrap_greenkey(greenkey)
newcell = MachineCodeEntryPoint(bridge, *greenargs)
Modified: pypy/trunk/pypy/rlib/jit.py
==============================================================================
--- pypy/trunk/pypy/rlib/jit.py (original)
+++ pypy/trunk/pypy/rlib/jit.py Thu Sep 10 12:12:41 2009
@@ -1,3 +1,4 @@
+import sys
from pypy.rpython.extregistry import ExtRegistryEntry
from pypy.rlib.objectmodel import CDefinedIntSymbolic
from pypy.rlib.unroll import unrolling_iterable
@@ -82,6 +83,8 @@
PARAMETERS = {'threshold': 1000,
'trace_eagerness': 200,
'hash_bits': 14,
+ 'trace_limit': 10000,
+ 'inlining': False,
}
unroll_parameters = unrolling_iterable(PARAMETERS.keys())
Modified: pypy/trunk/pypy/translator/driver.py
==============================================================================
--- pypy/trunk/pypy/translator/driver.py (original)
+++ pypy/trunk/pypy/translator/driver.py Thu Sep 10 12:12:41 2009
@@ -362,7 +362,7 @@
from pypy.jit.metainterp.warmspot import apply_jit
apply_jit(self.translator, policy=self.jitpolicy,
debug_level=self.config.translation.jit_debug,
- backend_name=self.config.translation.jit_backend)
+ backend_name=self.config.translation.jit_backend, inline=True)
#
self.log.info("the JIT compiler was generated")
#
More information about the Pypy-commit
mailing list