[pypy-svn] r78756 - in pypy/trunk/pypy: interpreter interpreter/test jit/codewriter jit/metainterp jit/metainterp/test module/pypyjit module/signal module/sys rlib

arigo at codespeak.net arigo at codespeak.net
Fri Nov 5 17:47:43 CET 2010


Author: arigo
Date: Fri Nov  5 17:47:41 2010
New Revision: 78756

Modified:
   pypy/trunk/pypy/interpreter/executioncontext.py
   pypy/trunk/pypy/interpreter/test/test_executioncontext.py
   pypy/trunk/pypy/jit/codewriter/jtransform.py
   pypy/trunk/pypy/jit/metainterp/blackhole.py
   pypy/trunk/pypy/jit/metainterp/pyjitpl.py
   pypy/trunk/pypy/jit/metainterp/test/test_basic.py
   pypy/trunk/pypy/module/pypyjit/interp_jit.py
   pypy/trunk/pypy/module/signal/interp_signal.py
   pypy/trunk/pypy/module/sys/__init__.py
   pypy/trunk/pypy/module/sys/vm.py
   pypy/trunk/pypy/rlib/jit.py
Log:
Merge branch/jit-signals.

JITted loops now call the action_dispatcher() less often if they are small.


Modified: pypy/trunk/pypy/interpreter/executioncontext.py
==============================================================================
--- pypy/trunk/pypy/interpreter/executioncontext.py	(original)
+++ pypy/trunk/pypy/interpreter/executioncontext.py	Fri Nov  5 17:47:41 2010
@@ -5,6 +5,8 @@
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib import jit
 
+TICK_COUNTER_STEP = 100
+
 def app_profile_call(space, w_callable, frame, event, w_arg):
     space.call_function(w_callable,
                         space.wrap(frame),
@@ -166,12 +168,12 @@
         if self.w_tracefunc is not None:
             self._trace(frame, 'return', w_retval)
 
-    def bytecode_trace(self, frame):
+    def bytecode_trace(self, frame, decr_by=TICK_COUNTER_STEP):
         "Trace function called before each bytecode."
         # this is split into a fast path and a slower path that is
         # not invoked every time bytecode_trace() is.
         actionflag = self.space.actionflag
-        if actionflag.decrement_ticker() < 0:
+        if actionflag.decrement_ticker(decr_by) < 0:
             actionflag.action_dispatcher(self, frame)     # slow path
     bytecode_trace._always_inline_ = True
 
@@ -333,6 +335,7 @@
         self._nonperiodic_actions = []
         self.has_bytecode_counter = False
         self.fired_actions = None
+        self.checkinterval_scaled = 100 * TICK_COUNTER_STEP
         self._rebuild_action_dispatcher()
 
     def fire(self, action):
@@ -361,10 +364,16 @@
             self.has_bytecode_counter = True
         self._rebuild_action_dispatcher()
 
-    def setcheckinterval(self, space, interval):
+    def getcheckinterval(self):
+        return self.checkinterval_scaled // TICK_COUNTER_STEP
+
+    def setcheckinterval(self, interval):
+        MAX = sys.maxint // TICK_COUNTER_STEP
         if interval < 1:
             interval = 1
-        space.sys.checkinterval = interval
+        elif interval > MAX:
+            interval = MAX
+        self.checkinterval_scaled = interval * TICK_COUNTER_STEP
 
     def _rebuild_action_dispatcher(self):
         periodic_actions = unrolling_iterable(self._periodic_actions)
@@ -372,7 +381,7 @@
         @jit.dont_look_inside
         def action_dispatcher(ec, frame):
             # periodic actions (first reset the bytecode counter)
-            self.reset_ticker(ec.space.sys.checkinterval)
+            self.reset_ticker(self.checkinterval_scaled)
             for action in periodic_actions:
                 action.perform(ec, frame)
 
@@ -399,10 +408,10 @@
     def reset_ticker(self, value):
         self._ticker = value
 
-    def decrement_ticker(self):
+    def decrement_ticker(self, by):
         value = self._ticker
         if self.has_bytecode_counter:    # this 'if' is constant-folded
-            value -= 1
+            value -= by
             self._ticker = value
         return value
 

Modified: pypy/trunk/pypy/interpreter/test/test_executioncontext.py
==============================================================================
--- pypy/trunk/pypy/interpreter/test/test_executioncontext.py	(original)
+++ pypy/trunk/pypy/interpreter/test/test_executioncontext.py	Fri Nov  5 17:47:41 2010
@@ -58,7 +58,8 @@
                 """)
         except Finished:
             pass
-        assert space.sys.checkinterval / 10 < i < space.sys.checkinterval * 1.1
+        checkinterval = space.actionflag.getcheckinterval()
+        assert checkinterval / 10 < i < checkinterval * 1.1
 
     def test_llprofile(self):
         l = []

Modified: pypy/trunk/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/trunk/pypy/jit/codewriter/jtransform.py	(original)
+++ pypy/trunk/pypy/jit/codewriter/jtransform.py	Fri Nov  5 17:47:41 2010
@@ -873,6 +873,8 @@
         elif oopspec_name == 'jit.assert_green':
             kind = getkind(args[0].concretetype)
             return SpaceOperation('%s_assert_green' % kind, args, None)
+        elif oopspec_name == 'jit.current_trace_length':
+            return SpaceOperation('current_trace_length', [], op.result)
         else:
             raise AssertionError("missing support for %r" % oopspec_name)
 

Modified: pypy/trunk/pypy/jit/metainterp/blackhole.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/blackhole.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/blackhole.py	Fri Nov  5 17:47:41 2010
@@ -774,6 +774,10 @@
     def bhimpl_float_assert_green(x):
         pass
 
+    @arguments(returns="i")
+    def bhimpl_current_trace_length():
+        return -1
+
     # ----------
     # the main hints and recursive calls
 

Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py	Fri Nov  5 17:47:41 2010
@@ -948,6 +948,11 @@
     opimpl_ref_assert_green   = _opimpl_assert_green
     opimpl_float_assert_green = _opimpl_assert_green
 
+    @arguments()
+    def opimpl_current_trace_length(self):
+        trace_length = len(self.metainterp.history.operations)
+        return ConstInt(trace_length)
+
     @arguments("box")
     def opimpl_virtual_ref(self, box):
         # Details on the content of metainterp.virtualref_boxes:

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	Fri Nov  5 17:47:41 2010
@@ -3,6 +3,7 @@
 from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside
 from pypy.rlib.jit import OPTIMIZER_FULL, OPTIMIZER_SIMPLE, loop_invariant
 from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed
+from pypy.rlib.jit import unroll_safe, current_trace_length
 from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
 from pypy.jit.backend.llgraph import runner
 from pypy.jit.metainterp import pyjitpl, history
@@ -1672,6 +1673,31 @@
         assert res == 8
         py.test.raises(AssertGreenFailed, self.interp_operations, f, [8, 0])
 
+    def test_current_trace_length(self):
+        myjitdriver = JitDriver(greens = ['g'], reds = ['x'])
+        @dont_look_inside
+        def residual():
+            print "hi there"
+        @unroll_safe
+        def loop(g):
+            y = 0
+            while y < g:
+                residual()
+                y += 1
+        def f(x, g):
+            n = 0
+            while x > 0:
+                myjitdriver.can_enter_jit(x=x, g=g)
+                myjitdriver.jit_merge_point(x=x, g=g)
+                loop(g)
+                x -= 1
+                n = current_trace_length()
+            return n
+        res = self.meta_interp(f, [5, 8])
+        assert 14 < res < 42
+        res = self.meta_interp(f, [5, 2])
+        assert 4 < res < 14
+
 
 class TestOOtype(BasicTests, OOJitMixin):
 

Modified: pypy/trunk/pypy/module/pypyjit/interp_jit.py
==============================================================================
--- pypy/trunk/pypy/module/pypyjit/interp_jit.py	(original)
+++ pypy/trunk/pypy/module/pypyjit/interp_jit.py	Fri Nov  5 17:47:41 2010
@@ -6,6 +6,7 @@
 from pypy.tool.pairtype import extendabletype
 from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside
+from pypy.rlib.jit import current_trace_length
 import pypy.interpreter.pyopcode   # for side-effects
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.gateway import ObjSpace, Arguments, W_Root
@@ -80,9 +81,22 @@
 
     def jump_absolute(self, jumpto, _, ec=None):
         if we_are_jitted():
+            # Normally, the tick counter is decremented by 100 for every
+            # Python opcode.  Here, to better support JIT compilation of
+            # small loops, we decrement it by a possibly smaller constant.
+            # We get the maximum 100 when the (unoptimized) trace length
+            # is at least 3200 (a bit randomly).
+            trace_length = r_uint(current_trace_length())
+            decr_by = trace_length // 32
+            if decr_by < 1:
+                decr_by = 1
+            elif decr_by > 100:    # also if current_trace_length() returned -1
+                decr_by = 100
+            #
             self.last_instr = intmask(jumpto)
-            ec.bytecode_trace(self)
+            ec.bytecode_trace(self, intmask(decr_by))
             jumpto = r_uint(self.last_instr)
+        #
         pypyjitdriver.can_enter_jit(frame=self, ec=ec, next_instr=jumpto,
                                     pycode=self.getcode())
         return jumpto

Modified: pypy/trunk/pypy/module/signal/interp_signal.py
==============================================================================
--- pypy/trunk/pypy/module/signal/interp_signal.py	(original)
+++ pypy/trunk/pypy/module/signal/interp_signal.py	Fri Nov  5 17:47:41 2010
@@ -65,11 +65,11 @@
         p = pypysig_getaddr_occurred()
         p.c_value = value
 
-    def decrement_ticker(self):
+    def decrement_ticker(self, by):
         p = pypysig_getaddr_occurred()
         value = p.c_value
         if self.has_bytecode_counter:    # this 'if' is constant-folded
-            value -= 1
+            value -= by
             p.c_value = value
         return value
 

Modified: pypy/trunk/pypy/module/sys/__init__.py
==============================================================================
--- pypy/trunk/pypy/module/sys/__init__.py	(original)
+++ pypy/trunk/pypy/module/sys/__init__.py	Fri Nov  5 17:47:41 2010
@@ -10,7 +10,6 @@
         if space.config.translating:
             del self.__class__.interpleveldefs['pypy_getudir']
         super(Module, self).__init__(space, w_name) 
-        self.checkinterval = 100
         self.recursionlimit = 100
         self.w_default_encoder = None
         self.defaultencoding = "ascii"

Modified: pypy/trunk/pypy/module/sys/vm.py
==============================================================================
--- pypy/trunk/pypy/module/sys/vm.py	(original)
+++ pypy/trunk/pypy/module/sys/vm.py	Fri Nov  5 17:47:41 2010
@@ -67,7 +67,7 @@
 def setcheckinterval(space, interval):
     """Tell the Python interpreter to check for asynchronous events every
     n instructions.  This also affects how often thread switches occur."""
-    space.actionflag.setcheckinterval(space, interval)
+    space.actionflag.setcheckinterval(interval)
 setcheckinterval.unwrap_spec = [ObjSpace, int]
 
 def getcheckinterval(space):
@@ -77,7 +77,7 @@
     # return 0.  The idea is that according to the CPython docs, <= 0
     # means "check every virtual instruction, maximizing responsiveness
     # as well as overhead".
-    result = space.sys.checkinterval
+    result = space.actionflag.getcheckinterval()
     if result <= 1:
         result = 0
     return space.wrap(result)

Modified: pypy/trunk/pypy/rlib/jit.py
==============================================================================
--- pypy/trunk/pypy/rlib/jit.py	(original)
+++ pypy/trunk/pypy/rlib/jit.py	Fri Nov  5 17:47:41 2010
@@ -4,6 +4,7 @@
 from pypy.rlib.objectmodel import CDefinedIntSymbolic
 from pypy.rlib.objectmodel import keepalive_until_here
 from pypy.rlib.unroll import unrolling_iterable
+from pypy.rlib.nonconst import NonConstant
 
 def purefunction(func):
     """ Decorate a function as pure. Pure means precisely that:
@@ -145,6 +146,14 @@
         return hop.inputconst(lltype.Signed, _we_are_jitted)
 
 
+def current_trace_length():
+    """During JIT tracing, returns the current trace length (as a constant).
+    If not tracing, returns -1."""
+    if NonConstant(False):
+        return 73
+    return -1
+current_trace_length.oopspec = 'jit.current_trace_length()'
+
 def jit_debug(string, arg1=-sys.maxint-1, arg2=-sys.maxint-1,
                       arg3=-sys.maxint-1, arg4=-sys.maxint-1):
     """When JITted, cause an extra operation DEBUG_MERGE_POINT to appear in



More information about the Pypy-commit mailing list