[pypy-commit] pypy counter-decay: Implement decaying. See comments.

arigo noreply at buildbot.pypy.org
Thu Dec 15 11:04:34 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: counter-decay
Changeset: r50539:b84533eb4350
Date: 2011-12-15 00:39 +0100
http://bitbucket.org/pypy/pypy/changeset/b84533eb4350/

Log:	Implement decaying. See comments.

diff --git a/pypy/jit/metainterp/memmgr.py b/pypy/jit/metainterp/memmgr.py
--- a/pypy/jit/metainterp/memmgr.py
+++ b/pypy/jit/metainterp/memmgr.py
@@ -1,5 +1,5 @@
 import math
-from pypy.rlib.rarithmetic import r_int64
+from pypy.rlib.rarithmetic import r_int64, r_uint
 from pypy.rlib.debug import debug_start, debug_print, debug_stop
 from pypy.rlib.objectmodel import we_are_translated
 
@@ -81,3 +81,8 @@
             # a single one is not enough for all tests :-(
             rgc.collect(); rgc.collect(); rgc.collect()
         debug_stop("jit-mem-collect")
+
+    def get_current_generation_uint(self):
+        """Return the current generation, possibly truncated to a uint.
+        To use only as an approximation for decaying counters."""
+        return r_uint(self.current_generation)
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
@@ -1557,13 +1557,6 @@
     in_recursion = 0
 
     def __init__(self, staticdata, jitdriver_sd):
-        try:
-            jitdriver_sd.warmstate.decay_counters
-        except AttributeError:   # for tests
-            pass
-        else:
-            jitdriver_sd.warmstate.decay_counters()
-        #
         self.staticdata = staticdata
         self.cpu = staticdata.cpu
         self.jitdriver_sd = jitdriver_sd
diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py
--- a/pypy/jit/metainterp/test/test_warmstate.py
+++ b/pypy/jit/metainterp/test/test_warmstate.py
@@ -1,3 +1,4 @@
+import math
 from pypy.rpython.test.test_llinterp import interpret
 from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi
 from pypy.rpython.ootypesystem import ootype
@@ -8,7 +9,7 @@
 from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr
 from pypy.jit.metainterp.history import ConstInt, ConstFloat, ConstPtr
 from pypy.jit.codewriter import longlong
-from pypy.rlib.rarithmetic import r_singlefloat
+from pypy.rlib.rarithmetic import r_singlefloat, r_uint
 
 def boxfloat(x):
     return BoxFloat(longlong.getfloatstorage(x))
@@ -277,4 +278,11 @@
     assert res is True
 
 def test_decay_counters():
-    xxx
+    cell = JitCell(r_uint(5))
+    cell.counter = 100
+    cell.adjust_counter(r_uint(5), math.log(0.9))
+    assert cell.counter == 100
+    cell.adjust_counter(r_uint(6), math.log(0.9))
+    assert cell.counter == 90
+    cell.adjust_counter(r_uint(9), math.log(0.9))
+    assert cell.counter == int(90 * (0.9**3))
diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py
--- a/pypy/jit/metainterp/warmstate.py
+++ b/pypy/jit/metainterp/warmstate.py
@@ -1,10 +1,10 @@
-import sys, weakref
+import sys, weakref, math
 from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.annlowlevel import hlstr, cast_base_ptr_to_instance
 from pypy.rpython.annlowlevel import cast_object_to_ptr
 from pypy.rlib.objectmodel import specialize, we_are_translated, r_dict
-from pypy.rlib.rarithmetic import intmask
+from pypy.rlib.rarithmetic import intmask, r_uint
 from pypy.rlib.nonconst import NonConstant
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.jit import PARAMETERS
@@ -153,6 +153,24 @@
     dont_trace_here = False
     wref_procedure_token = None
 
+    def __init__(self, generation):
+        # The stored 'counter' value follows an exponential decay model.
+        # Conceptually after every generation, it decays by getting
+        # multiplied by a constant <= 1.0.  In practice, decaying occurs
+        # lazily: the following field records the latest seen generation
+        # number, and adjustment is done by adjust_counter() when needed.
+        self.latest_generation_seen = generation
+
+    def adjust_counter(self, generation, log_decay_factor):
+        if generation != self.latest_generation_seen:
+            # The latest_generation_seen is older than the current generation.
+            # Adjust by multiplying self.counter N times by decay_factor, i.e.
+            # by decay_factor ** N, which is equal to exp(log(decay_factor)*N).
+            N = generation - self.latest_generation_seen
+            factor = math.exp(log_decay_factor * N)
+            self.counter = int(self.counter * factor)
+            self.latest_generation_seen = generation
+
     def get_procedure_token(self):
         if self.wref_procedure_token is not None:
             token = self.wref_procedure_token()
@@ -214,10 +232,15 @@
         self.inlining = value
 
     def set_param_decay_halflife(self, value):
-        if value <= 0:    # use 0 or -1 to mean "no decay"
-            self.decay_factor = 1.0
+        # Use 0 or -1 to mean "no decay".  Initialize the internal variable
+        # 'log_decay_factor'.  It is choosen such that by multiplying the
+        # counter on loops by 'exp(log_decay_factor)' (<= 1.0) every
+        # generation, then the counter will be divided by two after 'value'
+        # generations have passed.
+        if value <= 0:
+            self.log_decay_factor = 0.0    # log(1.0)
         else:
-            self.decay_factor = 0.5 ** (1.0 / value)
+            self.log_decay_factor = math.log(0.5) / value
 
     def set_param_enable_opts(self, value):
         from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT, ALL_OPTS_NAMES
@@ -288,6 +311,11 @@
         confirm_enter_jit = self.confirm_enter_jit
         range_red_args = unrolling_iterable(
             range(num_green_args, num_green_args + jitdriver_sd.num_red_args))
+        memmgr = self.warmrunnerdesc.memory_manager
+        if memmgr is not None:
+            get_current_generation = memmgr.get_current_generation_uint
+        else:
+            get_current_generation = lambda: r_uint(0)
         # get a new specialized copy of the method
         ARGS = []
         for kind in jitdriver_sd.red_args_types:
@@ -332,6 +360,8 @@
 
             if cell.counter >= 0:
                 # update the profiling counter
+                cell.adjust_counter(get_current_generation(),
+                                    self.log_decay_factor)
                 n = cell.counter + threshold
                 if n <= self.THRESHOLD_LIMIT:       # bound not reached
                     cell.counter = n
@@ -424,6 +454,15 @@
         #
         return jit_getter
 
+    def _new_jitcell(self):
+        warmrunnerdesc = self.warmrunnerdesc
+        if (warmrunnerdesc is not None and
+                warmrunnerdesc.memory_manager is not None):
+            gen = warmrunnerdesc.memory_manager.get_current_generation_uint()
+        else:
+            gen = r_uint(0)
+        return JitCell(gen)
+
     def _make_jitcell_getter_default(self):
         "NOT_RPYTHON"
         jitdriver_sd = self.jitdriver_sd
@@ -459,7 +498,7 @@
             except KeyError:
                 if not build:
                     return None
-                cell = JitCell()
+                cell = self._new_jitcell()
                 jitcell_dict[greenargs] = cell
             return cell
         return get_jitcell
@@ -491,7 +530,7 @@
             if not build:
                 return cell
             if cell is None:
-                cell = JitCell()
+                cell = self._new_jitcell()
                 # <hacks>
                 if we_are_translated():
                     cellref = cast_object_to_ptr(BASEJITCELL, cell)
diff --git a/pypy/rpython/rint.py b/pypy/rpython/rint.py
--- a/pypy/rpython/rint.py
+++ b/pypy/rpython/rint.py
@@ -126,10 +126,7 @@
     rtype_inplace_rshift = rtype_rshift
 
     def rtype_pow(_, hop):
-        raise MissingRTypeOperation("pow(int, int)"
-                                    " (use float**float instead; it is too"
-                                    " easy to overlook the overflow"
-                                    " issues of int**int)")
+        raise MissingRTypeOperation("'**' not supported in RPython")
 
     rtype_pow_ovf = rtype_pow
     rtype_inplace_pow = rtype_pow


More information about the pypy-commit mailing list