[pypy-commit] pypy jit-targets: a first failed atempt to support retrace, we need to redesign...

hakanardo noreply at buildbot.pypy.org
Sun Nov 6 14:10:45 CET 2011


Author: Hakan Ardo <hakan at debian.org>
Branch: jit-targets
Changeset: r48820:a91e6cab9119
Date: 2011-11-06 12:46 +0100
http://bitbucket.org/pypy/pypy/changeset/a91e6cab9119/

Log:	a first failed atempt to support retrace, we need to redesign...

diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -94,7 +94,7 @@
 
 def compile_procedure(metainterp, greenkey, start,
                       inputargs, jumpargs,
-                      start_resumedescr, full_preamble_needed=True):
+                      start_resumedescr, full_preamble_needed=True, partial_trace=None):
     """Try to compile a new procedure by closing the current history back
     to the first operation.
     """
@@ -104,22 +104,29 @@
     metainterp_sd = metainterp.staticdata
     jitdriver_sd = metainterp.jitdriver_sd
 
-    loop = create_empty_loop(metainterp)
-    loop.inputargs = inputargs[:]
-    
-    procedure_token = make_procedure_token(jitdriver_sd)
-    part = create_empty_loop(metainterp)
-    h_ops = history.operations
-    part.start_resumedescr = start_resumedescr
-    part.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(procedure_token))] + \
-                      [h_ops[i].clone() for i in range(start, len(h_ops))] + \
-                      [ResOperation(rop.LABEL, jumpargs, None, descr=TargetToken(procedure_token))]
-    try:
-        optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts)
-    except InvalidLoop:
-        return None
+    if partial_trace:
+        part = partial_trace
+        procedure_token = metainterp.get_procedure_token(greenkey)
+        assert procedure_token
+        all_target_tokens = []
+    else:
+        procedure_token = make_procedure_token(jitdriver_sd)
+        part = create_empty_loop(metainterp)
+        part.inputargs = inputargs[:]
+        h_ops = history.operations
+        part.start_resumedescr = start_resumedescr
+        part.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(procedure_token))] + \
+                          [h_ops[i].clone() for i in range(start, len(h_ops))] + \
+                          [ResOperation(rop.LABEL, jumpargs, None, descr=TargetToken(procedure_token))]
+        try:
+            optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts)
+        except InvalidLoop:
+            return None
+        all_target_tokens = [part.operations[0].getdescr()]
+
+    loop = create_empty_loop(metainterp)        
+    loop.inputargs = part.inputargs
     loop.operations = part.operations
-    all_target_tokens = [part.operations[0].getdescr()]
     while part.operations[-1].getopnum() == rop.LABEL:
         inliner = Inliner(inputargs, jumpargs)
         part.operations = [part.operations[-1]] + \
@@ -627,11 +634,11 @@
     # 
     # Attempt to use optimize_bridge().  This may return None in case
     # it does not work -- i.e. none of the existing old_loop_tokens match.
-    new_loop = create_empty_loop(metainterp)
-    new_loop.inputargs = inputargs = metainterp.history.inputargs[:]
+    new_trace = create_empty_loop(metainterp)
+    new_trace.inputargs = inputargs = metainterp.history.inputargs[:]
     # clone ops, as optimize_bridge can mutate the ops
 
-    new_loop.operations = [op.clone() for op in metainterp.history.operations]
+    new_trace.operations = [op.clone() for op in metainterp.history.operations]
     metainterp_sd = metainterp.staticdata
     state = metainterp.jitdriver_sd.warmstate
     if isinstance(resumekey, ResumeAtPositionDescr):
@@ -639,20 +646,25 @@
     else:
         inline_short_preamble = True
     try:
-        optimize_trace(metainterp_sd, new_loop, state.enable_opts)
+        optimize_trace(metainterp_sd, new_trace, state.enable_opts)
     except InvalidLoop:
         debug_print("compile_new_bridge: got an InvalidLoop")
         # XXX I am fairly convinced that optimize_bridge cannot actually raise
         # InvalidLoop
         debug_print('InvalidLoop in compile_new_bridge')
         return None
-    # We managed to create a bridge.  Dispatch to resumekey to
-    # know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr)
-    target_token = new_loop.operations[-1].getdescr()
-    resumekey.compile_and_attach(metainterp, new_loop)
-    record_loop_or_bridge(metainterp_sd, new_loop)
 
-    return target_token
+    if new_trace.operations[-1].getopnum() == rop.JUMP:
+        # We managed to create a bridge.  Dispatch to resumekey to
+        # know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr)
+        target_token = new_trace.operations[-1].getdescr()
+        resumekey.compile_and_attach(metainterp, new_trace)
+        record_loop_or_bridge(metainterp_sd, new_trace)
+        return target_token
+    else:
+        metainterp.retrace_needed(new_trace)
+        return None
+        
 
 # ____________________________________________________________
 
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -88,12 +88,18 @@
         if not stop_label:
             self.optimizer.flush()
             loop.operations = self.optimizer.get_newoperations()
+            return
         elif not start_label:
-            #jumpop = ResOperation(rop.JUMP, stop_label.getarglist(), None, descr=stop_label.getdescr())
-            self.optimizer.send_extra_operation(stop_label)
-            self.optimizer.flush()
-            loop.operations = self.optimizer.get_newoperations()
-        elif not self.did_peel_one: # Enforce the previous behaviour of always peeling  exactly one iteration (for now)
+            try:
+                self.optimizer.send_extra_operation(stop_label)
+            except RetraceLoop:
+                pass
+            else:
+                self.optimizer.flush()
+                loop.operations = self.optimizer.get_newoperations()
+                return
+
+        if not self.did_peel_one: # Enforce the previous behaviour of always peeling  exactly one iteration (for now)
             self.optimizer.flush()
             KillHugeIntBounds(self.optimizer).apply()
 
@@ -152,6 +158,7 @@
                                                     inputarg_setup_ops, self.optimizer)
 
     def import_state(self, targetop):
+        self.did_peel_one = False
         if not targetop:
             # FIXME: Set up some sort of empty state with no virtuals?
             return
@@ -161,7 +168,6 @@
         assert isinstance(target_token, TargetToken)
         exported_state = target_token.exported_state
         if not exported_state:
-            self.did_peel_one = False
             # FIXME: Set up some sort of empty state with no virtuals
             return
         self.did_peel_one = True
@@ -504,29 +510,31 @@
                     return
             debug_stop('jit-log-virtualstate')
             
-            if False: # FIXME: retrace
-                retraced_count = loop_token.retraced_count
-                limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit
-                if not self.retraced and retraced_count<limit:
-                    loop_token.retraced_count += 1
-                    if not loop_token.failed_states:
-                        debug_print("Retracing (%d of %d)" % (retraced_count,
-                                                              limit))
-                        raise RetraceLoop
-                    for failed in loop_token.failed_states:
-                        if failed.generalization_of(virtual_state):
-                            # Retracing once more will most likely fail again
-                            break
-                    else:
-                        debug_print("Retracing (%d of %d)" % (retraced_count,
-                                                              limit))
+            retraced_count = procedure_token.retraced_count
+            limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit
+            if not self.retraced and retraced_count<limit:
+                procedure_token.retraced_count += 1
+                raise RetraceLoop
 
-                        raise RetraceLoop
-                else:
-                    if not loop_token.failed_states:
-                        loop_token.failed_states=[virtual_state]
-                    else:
-                        loop_token.failed_states.append(virtual_state)
+            ## # We should not be failing much anymore...
+            ##     if not procedure_token.failed_states:
+            ##         debug_print("Retracing (%d of %d)" % (retraced_count,
+            ##                                               limit))
+            ##         raise RetraceLoop
+            ##     for failed in loop_token.failed_states:
+            ##         if failed.generalization_of(virtual_state):
+            ##             # Retracing once more will most likely fail again
+            ##             break
+            ##     else:
+            ##         debug_print("Retracing (%d of %d)" % (retraced_count,
+            ##                                               limit))
+
+            ##         raise RetraceLoop
+            ## else:
+            ##     if not loop_token.failed_states:
+            ##         loop_token.failed_states=[virtual_state]
+            ##     else:
+            ##         loop_token.failed_states.append(virtual_state)
         self.emit_operation(op)
 
 class ValueImporter(object):
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -22,7 +22,6 @@
 from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr
 from pypy.jit.codewriter import heaptracker
 from pypy.jit.metainterp.optimizeopt.util import args_dict_box
-from pypy.jit.metainterp.optimize import RetraceLoop
 
 # ____________________________________________________________
 
@@ -1557,10 +1556,17 @@
         self.portal_trace_positions = []
         self.free_frames_list = []
         self.last_exc_value_box = None
-        self.retracing_loop_from = None
+        self.partial_trace = None
+        self.retracing_from = -1
         self.call_pure_results = args_dict_box()
         self.heapcache = HeapCache()
 
+    def retrace_needed(self, trace):
+        self.partial_trace = trace
+        self.retracing_from = len(self.history)
+        self.heapcache.reset()
+        
+
     def perform_call(self, jitcode, boxes, greenkey=None):
         # causes the metainterp to enter the given subfunction
         f = self.newframe(jitcode, greenkey)
@@ -1928,14 +1934,8 @@
         #   that failed;
         # - if self.resumekey is a ResumeFromInterpDescr, it starts directly
         #   from the interpreter.
-        if not self.retracing_loop_from:
-            try:
-                self.compile_trace(live_arg_boxes)
-            except RetraceLoop:
-                start = len(self.history.operations)
-                self.current_merge_points.append((live_arg_boxes, start))
-                self.retracing_loop_from = RetraceState(self, live_arg_boxes)
-                return
+        if not self.partial_trace:
+            self.compile_trace(live_arg_boxes)
 
         # raises in case it works -- which is the common case, hopefully,
         # at least for bridges starting from a guard.
@@ -1957,14 +1957,9 @@
             else:
                 # Found!  Compile it as a loop.
                 # raises in case it works -- which is the common case
-                if self.retracing_loop_from and \
-                   self.retracing_loop_from.merge_point == j:
-                    bridge_arg_boxes = self.retracing_loop_from.live_arg_boxes
-                    self.compile_bridge_and_loop(original_boxes, \
-                                                 live_arg_boxes, start,
-                                                 bridge_arg_boxes, resumedescr)
-                else:
-                    self.compile_procedure(original_boxes, live_arg_boxes, start, resumedescr)
+                if self.partial_trace:
+                    assert start == self.retracing_from # FIXME: Giveup
+                self.compile_procedure(original_boxes, live_arg_boxes, start, resumedescr)
                 # creation of the loop was cancelled!
                 self.staticdata.log('cancelled, tracing more...')
                 #self.staticdata.log('cancelled, stopping tracing')
@@ -2027,11 +2022,12 @@
     def compile_procedure(self, original_boxes, live_arg_boxes, start, start_resumedescr):
         num_green_args = self.jitdriver_sd.num_green_args
         greenkey = original_boxes[:num_green_args]
-        assert self.get_procedure_token(greenkey) == None # FIXME: recursion?
+        if not self.partial_trace:
+            assert self.get_procedure_token(greenkey) == None # FIXME: recursion?
         procedure_token = compile.compile_procedure(self, greenkey, start,
                                                     original_boxes[num_green_args:],
                                                     live_arg_boxes[num_green_args:],
-                                                    start_resumedescr)
+                                                    start_resumedescr, partial_trace=self.partial_trace)
         if procedure_token is not None: # raise if it *worked* correctly
             self.jitdriver_sd.warmstate.attach_procedure_to_interp(greenkey, procedure_token)
             self.history.inputargs = None


More information about the pypy-commit mailing list