[pypy-svn] r65219 - pypy/branch/pyjitpl5/pypy/jit/metainterp

arigo at codespeak.net arigo at codespeak.net
Mon May 11 18:12:58 CEST 2009


Author: arigo
Date: Mon May 11 18:12:57 2009
New Revision: 65219

Modified:
   pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/warmspot.py
Log:
Don't use UnboxedValue any more.  The current approach is only sightly
more indirect (after translation), but it probably makes little time
difference.


Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py	Mon May 11 18:12:57 2009
@@ -960,11 +960,7 @@
         state = staticdata.state
         if state is not None:
             self.unpack_greenkey = state.unwrap_greenkey
-            def mp_eq(greenargs1, greenargs2):
-                return state.comparekey(greenargs1, greenargs2)
-            def mp_hash(greenargs):
-                return intmask(state.getkeyhash(*greenargs))
-            self.compiled_merge_points = r_dict(mp_eq, mp_hash)
+            self.compiled_merge_points = r_dict(state.comparekey,state.hashkey)
                 # { (greenargs): [MergePoints] }
         else:
             self.compiled_merge_points = {}    # for tests only; not RPython

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/warmspot.py	Mon May 11 18:12:57 2009
@@ -11,7 +11,7 @@
 from pypy.rlib.objectmodel import we_are_translated, UnboxedValue, specialize
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.jit import PARAMETERS
-from pypy.rlib.rarithmetic import r_uint
+from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.rlib.debug import debug_print
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.translator.simplify import get_funcobj, get_functype
@@ -59,6 +59,7 @@
     warmrunnerdesc = WarmRunnerDesc(translator, **kwds)
     warmrunnerdesc.state.set_param_threshold(3)          # for tests
     warmrunnerdesc.state.set_param_trace_eagerness(2)    # for tests
+    warmrunnerdesc.state.create_tables_now()             # for tests
     if hash_bits:
         warmrunnerdesc.state.set_param_hash_bits(hash_bits)
     warmrunnerdesc.finish()
@@ -507,31 +508,28 @@
     warmrunnerdesc.num_green_args = num_green_args
     green_args_spec = unrolling_iterable(warmrunnerdesc.green_args_spec)
     green_args_names = unrolling_iterable(jitdriver.greens)
+    green_args_spec_names = unrolling_iterable(zip(
+        warmrunnerdesc.green_args_spec, jitdriver.greens))
     red_args_types = unrolling_iterable(warmrunnerdesc.red_args_types)
     if num_green_args:
         MAX_HASH_TABLE_BITS = 28
     else:
-        MAX_HASH_TABLE_BITS = 0
-    THRESHOLD_MAX = (sys.maxint-1) / 2
+        MAX_HASH_TABLE_BITS = 1
+    THRESHOLD_LIMIT = sys.maxint // 2
 
-    class StateCell(object):
-        __slots__ = []
-
-    class Counter(StateCell, UnboxedValue):
-        __slots__ = 'counter'
-
-    class MachineCodeEntryPoint(StateCell):
+    class MachineCodeEntryPoint(object):
+        next = None    # linked list
         def __init__(self, bridge, *greenargs):
             self.bridge = bridge
-            self.next = Counter(0)
             i = 0
             for name in green_args_names:
                 setattr(self, 'green_' + name, greenargs[i])
                 i = i + 1
         def equalkey(self, *greenargs):
             i = 0
-            for name in green_args_names:
-                if getattr(self, 'green_' + name) != greenargs[i]:
+            for TYPE, name in green_args_spec_names:
+                myvalue = getattr(self, 'green_' + name)
+                if not equal_whatever(TYPE, myvalue, greenargs[i]):
                     return False
                 i = i + 1
             return True
@@ -561,47 +559,60 @@
                 meth(default_value)
 
         def set_param_threshold(self, threshold):
-            if threshold > THRESHOLD_MAX:
-                threshold = THRESHOLD_MAX
-            self.threshold = threshold
+            if threshold < 2:
+                threshold = 2
+            self.increment_threshold = (THRESHOLD_LIMIT // threshold) + 1
+            # the number is at least 1, and at most about half THRESHOLD_LIMIT
 
         def set_param_trace_eagerness(self, value):
             self.trace_eagerness = value
 
         def set_param_hash_bits(self, value):
-            if value < 0:
-                value = 0
+            if value < 1:
+                value = 1
             elif value > MAX_HASH_TABLE_BITS:
                 value = MAX_HASH_TABLE_BITS
-            self.cells = [Counter(0)] * (1 << value)
-            self.hashtablemask = (1 << value) - 1
-
-            # Only use the hash of the arguments as the profiling key.
-            # Indeed, this is all a heuristic, so if things are designed
-            # correctly, the occasional mistake due to hash collision is
-            # not too bad.
+            # the tables are initialized with the correct size only in
+            # attach_unoptimized_bridge_from_interp()
+            self.hashbits = value
+            self.hashtablemask = 0
+            self.mccounters = [0]
+            self.mcentrypoints = [None]
+            # invariant: (self.mccounters[j] < 0) if and only if
+            #            (self.mcentrypoints[j] is not None)
+
+        def create_tables_now(self):
+            count = 1 << self.hashbits
+            self.hashtablemask = count - 1
+            self.mccounters = [0] * count
+            self.mcentrypoints = [None] * count
+
+        # Only use the hash of the arguments as the profiling key.
+        # Indeed, this is all a heuristic, so if things are designed
+        # correctly, the occasional mistake due to hash collision is
+        # not too bad.
 
         def maybe_compile_and_run(self, *args):
             # get the greenargs and look for the cell corresponding to the hash
             greenargs = args[:num_green_args]
             argshash = self.getkeyhash(*greenargs) & self.hashtablemask
-            cell = self.cells[argshash]
-            if isinstance(cell, Counter):
+            counter = self.mccounters[argshash]
+            if counter >= 0:
                 # update the profiling counter
-                n = cell.counter + 1
-                if n < self.threshold:
-                    #if hotrunnerdesc.verbose_level >= 3:
-                    #    interp.debug_trace("jit_not_entered", *args)
-                    self.cells[argshash] = Counter(n)
+                n = counter + self.increment_threshold
+                if n <= THRESHOLD_LIMIT:       # bound not reached
+                    self.mccounters[argshash] = n
+                    return
+                if self.hashtablemask == 0: # must really create the tables now
+                    self.create_tables_now()
                     return
-                #interp.debug_trace("jit_compile", *greenargs)
                 metainterp_sd = warmrunnerdesc.metainterp_sd
                 metainterp = MetaInterp(metainterp_sd)
                 loop = metainterp.compile_and_run_once(*args)
             else:
                 # machine code was already compiled for these greenargs
                 # (or we have a hash collision)
-                assert isinstance(cell, MachineCodeEntryPoint)
+                cell = self.mcentrypoints[argshash]
                 if not cell.equalkey(*greenargs):
                     # hash collision
                     loop = self.handle_hash_collision(cell, argshash, *args)
@@ -621,25 +632,27 @@
                 loop = fail_op.descr.handle_fail_op(metainterp_sd, fail_op)
         maybe_compile_and_run._dont_inline_ = True
 
-        def handle_hash_collision(self, cell, argshash, *args):
+        def handle_hash_collision(self, firstcell, argshash, *args):
             greenargs = args[:num_green_args]
-            next = cell.next
-            while not isinstance(next, Counter):
-                assert isinstance(next, MachineCodeEntryPoint)
-                if next.equalkey(*greenargs):
+            # search the linked list for the correct cell
+            cell = firstcell
+            while cell.next is not None:
+                nextcell = cell.next
+                if nextcell.equalkey(*greenargs):
                     # found, move to the front of the linked list
-                    cell.next = next.next
-                    next.next = self.cells[argshash]
-                    self.cells[argshash] = next
+                    cell.next = nextcell.next
+                    nextcell.next = firstcell
+                    self.mcentrypoints[argshash] = nextcell
                     cpu = warmrunnerdesc.metainterp_sd.cpu
-                    next.set_future_values(cpu, *args[num_green_args:])
-                    return next.bridge
-                cell = next
-                next = cell.next
+                    nextcell.set_future_values(cpu, *args[num_green_args:])
+                    return nextcell.bridge
+                cell = nextcell
             # not found at all, do profiling
-            n = next.counter + 1
-            if n < self.threshold:
-                cell.next = Counter(n)
+            counter = self.mccounters[argshash]
+            assert counter < 0          # by invariant
+            n = counter + self.increment_threshold
+            if n < 0:      # bound not reached
+                self.mccounters[argshash] = n
                 return None
             metainterp_sd = warmrunnerdesc.metainterp_sd
             metainterp = MetaInterp(metainterp_sd)
@@ -652,18 +665,23 @@
             for TYPE in green_args_spec:
                 value = unwrap(TYPE, greenkey[i])
                 greenargs += (value,)
-                i += 1
+                i = i + 1
             return greenargs
+        unwrap_greenkey._always_inline_ = True
 
-        def comparekey(self, greenargs1, greenargs2):
+        def comparekey(greenargs1, greenargs2):
             i = 0
             for TYPE in green_args_spec:
                 if not equal_whatever(TYPE, greenargs1[i], greenargs2[i]):
                     return False
             return True
-        comparekey._always_inline_ = True
+        comparekey = staticmethod(comparekey)
+
+        def hashkey(greenargs):
+            return intmask(WarmEnterState.getkeyhash(*greenargs))
+        hashkey = staticmethod(hashkey)
 
-        def getkeyhash(self, *greenargs):
+        def getkeyhash(*greenargs):
             result = r_uint(0x345678)
             i = 0
             mult = r_uint(1000003)
@@ -674,8 +692,9 @@
                 item = greenargs[i]
                 result = result ^ cast_whatever_to_int(TYPE, item)
                 i = i + 1
-            return result
+            return result         # returns a r_uint
         getkeyhash._always_inline_ = True
+        getkeyhash = staticmethod(getkeyhash)
 
         def must_compile_from_failure(self, key):
             key.counter += 1
@@ -685,16 +704,9 @@
             greenargs = self.unwrap_greenkey(greenkey)
             newcell = MachineCodeEntryPoint(bridge, *greenargs)
             argshash = self.getkeyhash(*greenargs) & self.hashtablemask
-            cell = self.cells[argshash]
-            if not isinstance(cell, Counter):
-                while True:
-                    assert isinstance(cell, MachineCodeEntryPoint)
-                    next = cell.next
-                    if isinstance(next, Counter):
-                        cell.next = Counter(0)
-                        break
-                    cell = next
-                newcell.next = self.cells[argshash]
-            self.cells[argshash] = newcell
+            oldcell = self.mcentrypoints[argshash]
+            newcell.next = oldcell     # link
+            self.mcentrypoints[argshash] = newcell
+            self.mccounters[argshash] = -THRESHOLD_LIMIT-1
 
     return WarmEnterState



More information about the Pypy-commit mailing list