[pypy-svn] r79148 - in pypy/branch/jit-free/pypy/jit: backend backend/llgraph metainterp metainterp/test
arigo at codespeak.net
arigo at codespeak.net
Tue Nov 16 15:49:37 CET 2010
Author: arigo
Date: Tue Nov 16 15:49:35 2010
New Revision: 79148
Modified:
pypy/branch/jit-free/pypy/jit/backend/llgraph/llimpl.py
pypy/branch/jit-free/pypy/jit/backend/llgraph/runner.py
pypy/branch/jit-free/pypy/jit/backend/model.py
pypy/branch/jit-free/pypy/jit/metainterp/compile.py
pypy/branch/jit-free/pypy/jit/metainterp/history.py
pypy/branch/jit-free/pypy/jit/metainterp/memmgr.py
pypy/branch/jit-free/pypy/jit/metainterp/test/test_memmgr.py
Log:
(antocuni, arigo)
* Make even more sure that loops are freed.
* Make the llgraph backend complain as soon as we are
trying to run a freed loop.
* Write a failing test for the memory manager.
The fix is setting the _keepalive_target_looktokens.
Modified: pypy/branch/jit-free/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/backend/llgraph/llimpl.py (original)
+++ pypy/branch/jit-free/pypy/jit/backend/llgraph/llimpl.py Tue Nov 16 15:49:35 2010
@@ -161,6 +161,8 @@
# ____________________________________________________________
class CompiledLoop(object):
+ has_been_freed = False
+
def __init__(self):
self.inputargs = []
self.operations = []
@@ -285,6 +287,11 @@
del _variables[:]
return _to_opaque(CompiledLoop())
+def mark_as_free(loop):
+ loop = _from_opaque(loop)
+ assert not loop.has_been_freed
+ loop.has_been_freed = True
+
def compile_start_int_var(loop):
return compile_start_ref_var(loop, lltype.Signed)
@@ -429,6 +436,7 @@
verbose = True
self.opindex = 0
while True:
+ assert not self.loop.has_been_freed
op = self.loop.operations[self.opindex]
args = [self.getenv(v) for v in op.args]
if not op.is_final():
@@ -1609,6 +1617,7 @@
setannotation(compile_add_fail, annmodel.SomeInteger())
setannotation(compile_add_fail_arg, annmodel.s_None)
setannotation(compile_redirect_fail, annmodel.s_None)
+setannotation(mark_as_free, annmodel.s_None)
setannotation(new_frame, s_Frame)
setannotation(frame_clear, annmodel.s_None)
Modified: pypy/branch/jit-free/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/backend/llgraph/runner.py (original)
+++ pypy/branch/jit-free/pypy/jit/backend/llgraph/runner.py Tue Nov 16 15:49:35 2010
@@ -118,8 +118,10 @@
self._descrs[key] = descr
return descr
- def compile_bridge(self, faildescr, inputargs, operations, log=True):
+ def compile_bridge(self, faildescr, inputargs, operations,
+ original_loop_token, log=True):
c = llimpl.compile_start()
+ original_loop_token._llgraph_loop_and_bridges.append(c)
self._compile_loop_or_bridge(c, inputargs, operations)
old, oldindex = faildescr._compiled_fail
llimpl.compile_redirect_fail(old, oldindex, c)
@@ -131,9 +133,15 @@
is not.
"""
c = llimpl.compile_start()
+ assert not hasattr(loopdescr, '_llgraph_loop_and_bridges')
+ loopdescr._llgraph_loop_and_bridges = [c]
loopdescr._llgraph_compiled_version = c
self._compile_loop_or_bridge(c, inputargs, operations)
+ def free_loop_and_bridges(self, looptoken):
+ for c in looptoken._llgraph_loop_and_bridges:
+ llimpl.mark_as_free(c)
+
def _compile_loop_or_bridge(self, c, inputargs, operations):
var2index = {}
for box in inputargs:
Modified: pypy/branch/jit-free/pypy/jit/backend/model.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/backend/model.py (original)
+++ pypy/branch/jit-free/pypy/jit/backend/model.py Tue Nov 16 15:49:35 2010
@@ -49,7 +49,8 @@
"""
raise NotImplementedError
- def compile_bridge(self, faildescr, inputargs, operations, log=True):
+ def compile_bridge(self, faildescr, inputargs, operations,
+ original_loop_token, log=True):
"""Assemble the bridge.
The FailDescr is the descr of the original guard that failed.
"""
Modified: pypy/branch/jit-free/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/metainterp/compile.py (original)
+++ pypy/branch/jit-free/pypy/jit/metainterp/compile.py Tue Nov 16 15:49:35 2010
@@ -82,6 +82,7 @@
send_loop_to_backend(metainterp_sd, loop, "loop")
insert_loop_token(old_loop_tokens, loop_token)
# mostly for tests: make sure we don't keep a reference to the LoopToken
+ metainterp.original_loop_token.record_loop_or_bridge(loop)
loop.token = None
metainterp.original_loop_token = None
return loop_token
@@ -127,7 +128,8 @@
if metainterp_sd.warmrunnerdesc is not None: # for tests
metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(loop.token)
-def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations):
+def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations,
+ original_loop_token):
n = metainterp_sd.cpu.get_fail_descr_number(faildescr)
metainterp_sd.logger_ops.log_bridge(inputargs, operations, n)
if not we_are_translated():
@@ -136,7 +138,8 @@
metainterp_sd.profiler.start_backend()
debug_start("jit-backend")
try:
- metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations)
+ metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations,
+ original_loop_token)
finally:
debug_stop("jit-backend")
metainterp_sd.profiler.end_backend()
@@ -326,7 +329,8 @@
if not we_are_translated():
self._debug_suboperations = new_loop.operations
send_bridge_to_backend(metainterp.staticdata, self, inputargs,
- new_loop.operations)
+ new_loop.operations,
+ metainterp.original_loop_token)
def copy_all_attrbutes_into(self, res):
# XXX a bit ugly to have to list them all here
@@ -510,10 +514,6 @@
old_loop_tokens.append(new_loop_token)
metainterp.set_compiled_merge_points(new_loop_token.outermost_greenkey,
old_loop_tokens)
- # mostly for tests: make sure we don't keep a reference
- # to the LoopToken
- new_loop.token = None
- metainterp.original_loop_token = None
def reset_counter_from_failure(self):
pass
@@ -548,6 +548,11 @@
# know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr)
prepare_last_operation(new_loop, target_loop_token)
resumekey.compile_and_attach(metainterp, new_loop)
+ # mostly for tests: make sure we don't keep a reference
+ # to the LoopToken
+ metainterp.original_loop_token.record_loop_or_bridge(new_loop)
+ metainterp.original_loop_token = None
+ new_loop.token = None
return target_loop_token
def prepare_last_operation(new_loop, target_loop_token):
Modified: pypy/branch/jit-free/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/metainterp/history.py (original)
+++ pypy/branch/jit-free/pypy/jit/metainterp/history.py Tue Nov 16 15:49:35 2010
@@ -744,9 +744,18 @@
# this loop or to a bridge attached to it.
self.faildescr_indices = []
# For memory management of assembled loops
- self.contains_jumps_to = {} # set of other LoopTokens
+ self._keepalive_target_looktokens = {} # set of other LoopTokens
self.generation = r_longlong(0)
+ def record_loop_or_bridge(self, loop):
+ # Records that the loop starting at the LoopToken 'self' ends up
+ # with 'loop', which may be either the loop itself or some pseudo-
+ # loop representing some bridge.
+ other_loop_token = loop.operations[-1].getdescr()
+ if isinstance(other_loop_token, LoopToken):
+ self._keepalive_target_looktokens[other_loop_token] = None
+ loop.operations[-1].setdescr(None) # clear reference
+
def __del__(self):
for i in range(160):
print '#',
Modified: pypy/branch/jit-free/pypy/jit/metainterp/memmgr.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/metainterp/memmgr.py (original)
+++ pypy/branch/jit-free/pypy/jit/metainterp/memmgr.py Tue Nov 16 15:49:35 2010
@@ -1,6 +1,7 @@
import math
from pypy.rlib.rarithmetic import r_longlong
from pypy.rlib.debug import debug_start, debug_print, debug_stop
+from pypy.rlib.objectmodel import we_are_translated
#
# Logic to decide which loops are old and not used any more.
@@ -71,3 +72,6 @@
debug_print("Loop tokens left: ", newtotal)
print self.alive_loops.keys()
debug_stop("jit-free-memmgr")
+ if not we_are_translated():
+ from pypy.rlib import rgc
+ rgc.collect()
Modified: pypy/branch/jit-free/pypy/jit/metainterp/test/test_memmgr.py
==============================================================================
--- pypy/branch/jit-free/pypy/jit/metainterp/test/test_memmgr.py (original)
+++ pypy/branch/jit-free/pypy/jit/metainterp/test/test_memmgr.py Tue Nov 16 15:49:35 2010
@@ -80,6 +80,37 @@
# we should see only the loop and the entry bridge
self.check_tree_loop_count(2)
+ def test_target_loop_kept_alive(self):
+ myjitdriver = JitDriver(greens=['m'], reds=['n'])
+ def g(m):
+ n = 10
+ while n > 0:
+ myjitdriver.can_enter_jit(n=n, m=m)
+ myjitdriver.jit_merge_point(n=n, m=m)
+ n = n - 1
+ return 21
+ import gc
+ def f():
+ # create the loop and the entry bridge for 'g(5)'
+ for i in range(8):
+ g(5)
+ # create another loop and another entry bridge for 'g(7)',
+ # to increase the current_generation
+ for i in range(20):
+ g(7)
+ # reuse the existing loop and entry bridge for 'g(5)'.
+ # the generation of the entry bridge for g(5) should never
+ # grow too old. The loop itself gets old, but is kept alive
+ # by the entry bridge via contains_jumps_to.
+ g(5)
+ return 42
+
+ res = self.meta_interp(f, [], loop_longevity=3)
+ assert res == 42
+
+ # we should see only the loop and the entry bridge for g(5) and g(7)
+ self.check_tree_loop_count(4)
+
# we need another test that fails because we store
# self._debug_suboperations in compile.py
More information about the Pypy-commit
mailing list