[pypy-commit] pypy default: Un-merge counter-decay, which was definitely not really good.
arigo
noreply at buildbot.pypy.org
Tue Dec 20 09:42:31 CET 2011
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r50744:a2b9604a9859
Date: 2011-12-20 08:57 +0100
http://bitbucket.org/pypy/pypy/changeset/a2b9604a9859/
Log: Un-merge counter-decay, which was definitely not really good. More
work should be going on in the branch.
This cancels 5309a1389556, e790db7af776 and 15811e23d71a.
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, r_uint
+from pypy.rlib.rarithmetic import r_int64
from pypy.rlib.debug import debug_start, debug_print, debug_stop
from pypy.rlib.objectmodel import we_are_translated
@@ -21,7 +21,6 @@
#
class MemoryManager(object):
- NO_NEXT_CHECK = r_int64(2 ** 63 - 1)
def __init__(self):
self.check_frequency = -1
@@ -37,13 +36,12 @@
# According to my estimates it's about 5e9 years given 1000 loops
# per second
self.current_generation = r_int64(1)
- self.next_check = self.NO_NEXT_CHECK
+ self.next_check = r_int64(-1)
self.alive_loops = {}
- self._cleanup_jitcell_dicts = lambda: None
def set_max_age(self, max_age, check_frequency=0):
if max_age <= 0:
- self.next_check = self.NO_NEXT_CHECK
+ self.next_check = r_int64(-1)
else:
self.max_age = max_age
if check_frequency <= 0:
@@ -51,11 +49,10 @@
self.check_frequency = check_frequency
self.next_check = self.current_generation + 1
- def next_generation(self, do_cleanups_now=True):
+ def next_generation(self):
self.current_generation += 1
- if do_cleanups_now and self.current_generation >= self.next_check:
+ if self.current_generation == self.next_check:
self._kill_old_loops_now()
- self._cleanup_jitcell_dicts()
self.next_check = self.current_generation + self.check_frequency
def keep_loop_alive(self, looptoken):
@@ -84,22 +81,3 @@
# 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)
-
- def record_jitcell_dict(self, callback):
- """NOT_RPYTHON. The given jitcell_dict is a dict that needs
- occasional clean-ups of old cells. A cell is old if it never
- reached the threshold, and its counter decayed to a tiny value."""
- # note that the various jitcell_dicts have different RPython types,
- # so we have to make a different function for each one. These
- # functions are chained to each other: each calls the previous one.
- def cleanup_dict():
- callback()
- cleanup_previous()
- #
- cleanup_previous = self._cleanup_jitcell_dicts
- self._cleanup_jitcell_dicts = cleanup_dict
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -2910,27 +2910,6 @@
res = self.meta_interp(f, [32])
assert res == f(32)
- def test_decay_counters(self):
- myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
- def f(m, n):
- while n > 0:
- myjitdriver.jit_merge_point(m=m, n=n)
- n += m
- n -= m
- n -= 1
- def main():
- f(5, 7) # run 7x with m=5 counter[m=5] = 7
- f(15, 10) # compiles one loop counter[m=5] = 3 (automatic decay)
- f(5, 5) # run 5x times with m=5 counter[m=5] = 8
- #
- self.meta_interp(main, [], decay_halflife=1,
- function_threshold=0, threshold=9, trace_eagerness=99)
- self.check_trace_count(1)
- #
- self.meta_interp(main, [], decay_halflife=1,
- function_threshold=0, threshold=8, trace_eagerness=99)
- self.check_trace_count(2)
-
class TestOOtype(BasicTests, OOJitMixin):
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,4 +1,3 @@
-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
@@ -9,7 +8,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, r_uint
+from pypy.rlib.rarithmetic import r_singlefloat
def boxfloat(x):
return BoxFloat(longlong.getfloatstorage(x))
@@ -276,77 +275,3 @@
state.make_jitdriver_callbacks()
res = state.can_never_inline(5, 42.5)
assert res is True
-
-def test_decay_counters():
- 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))
-
-def test_cleanup_jitcell_dict():
- from pypy.jit.metainterp.memmgr import MemoryManager
- class FakeWarmRunnerDesc:
- memory_manager = MemoryManager()
- class cpu:
- pass
- class FakeJitDriverSD:
- _green_args_spec = [lltype.Signed]
- #
- # Test creating tons of jitcells that remain at 0
- warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
- get_jitcell = warmstate._make_jitcell_getter_default()
- cell1 = get_jitcell(True, -1)
- assert len(warmstate._jitcell_dict) == 1
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 1
- #
- for i in range(1, 20005):
- get_jitcell(True, i) # should trigger a clean-up at 20001
- assert len(warmstate._jitcell_dict) == (i % 20000) + 1
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 2
- #
- # Same test, with one jitcell that has a counter of BASE instead of 0
- warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
- warmstate.set_param_decay_halflife(2)
- warmstate.set_param_threshold(5)
- warmstate.set_param_function_threshold(0)
- get_jitcell = warmstate._make_jitcell_getter_default()
- cell2 = get_jitcell(True, -2)
- cell2.counter = BASE = warmstate.increment_threshold * 3
- #
- for i in range(0, 20005):
- get_jitcell(True, i)
- assert len(warmstate._jitcell_dict) == (i % 19999) + 2
- #
- assert cell2 in warmstate._jitcell_dict.values()
- assert cell2.counter == int(BASE * math.sqrt(0.5)) # decayed once
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 3
- #
- # Same test, with jitcells that are compiled and free by the memmgr
- warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
- get_jitcell = warmstate._make_jitcell_getter_default()
- get_jitcell(True, -1)
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 3
- #
- for i in range(1, 20005):
- cell = get_jitcell(True, i)
- cell.counter = -1
- cell.wref_procedure_token = None # or a dead weakref, equivalently
- assert len(warmstate._jitcell_dict) == (i % 20000) + 1
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 4
- #
- # Same test, with counter == -2 (rare case, kept alive)
- warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
- get_jitcell = warmstate._make_jitcell_getter_default()
- cell = get_jitcell(True, -1)
- cell.counter = -2
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 4
- #
- for i in range(1, 20005):
- cell = get_jitcell(True, i)
- cell.counter = -2
- assert len(warmstate._jitcell_dict) == i + 1
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 5
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -64,11 +64,9 @@
def jittify_and_run(interp, graph, args, repeat=1, graph_and_interp_only=False,
backendopt=False, trace_limit=sys.maxint,
- threshold=3, trace_eagerness=2,
inline=False, loop_longevity=0, retrace_limit=5,
- function_threshold=4, decay_halflife=0,
- enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15,
- **kwds):
+ function_threshold=4,
+ enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15, **kwds):
from pypy.config.config import ConfigError
translator = interp.typer.annotator.translator
try:
@@ -85,16 +83,15 @@
pass
warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds)
for jd in warmrunnerdesc.jitdrivers_sd:
- jd.warmstate.set_param_threshold(threshold)
+ jd.warmstate.set_param_threshold(3) # for tests
jd.warmstate.set_param_function_threshold(function_threshold)
- jd.warmstate.set_param_trace_eagerness(trace_eagerness)
+ jd.warmstate.set_param_trace_eagerness(2) # for tests
jd.warmstate.set_param_trace_limit(trace_limit)
jd.warmstate.set_param_inlining(inline)
jd.warmstate.set_param_loop_longevity(loop_longevity)
jd.warmstate.set_param_retrace_limit(retrace_limit)
jd.warmstate.set_param_max_retrace_guards(max_retrace_guards)
jd.warmstate.set_param_enable_opts(enable_opts)
- jd.warmstate.set_param_decay_halflife(decay_halflife)
warmrunnerdesc.finish()
if graph_and_interp_only:
return interp, graph
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, math
+import sys, weakref
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, r_uint
+from pypy.rlib.rarithmetic import intmask
from pypy.rlib.nonconst import NonConstant
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.jit import PARAMETERS
@@ -153,25 +153,6 @@
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).
- assert self.counter >= 0
- 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()
@@ -191,6 +172,7 @@
class WarmEnterState(object):
THRESHOLD_LIMIT = sys.maxint // 2
+ default_jitcell_dict = None
def __init__(self, warmrunnerdesc, jitdriver_sd):
"NOT_RPYTHON"
@@ -231,17 +213,6 @@
def set_param_inlining(self, value):
self.inlining = value
- def set_param_decay_halflife(self, value):
- # 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.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
@@ -311,11 +282,6 @@
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:
@@ -360,8 +326,6 @@
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
@@ -454,15 +418,6 @@
#
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
@@ -492,53 +447,13 @@
except AttributeError:
pass
#
- memmgr = self.warmrunnerdesc and self.warmrunnerdesc.memory_manager
- if memmgr:
- def _cleanup_dict():
- minimum = sys.maxint
- if self.increment_threshold > 0:
- minimum = min(minimum, self.increment_threshold)
- if self.increment_function_threshold > 0:
- minimum = min(minimum, self.increment_function_threshold)
- currentgen = memmgr.get_current_generation_uint()
- killme = []
- for key, cell in jitcell_dict.iteritems():
- if cell.counter >= 0:
- cell.adjust_counter(currentgen, self.log_decay_factor)
- if cell.counter < minimum:
- killme.append(key)
- elif (cell.counter == -1
- and cell.get_procedure_token() is None):
- killme.append(key)
- for key in killme:
- del jitcell_dict[key]
- #
- def _maybe_cleanup_dict():
- # If no tracing goes on at all because the jitcells are
- # each time for new greenargs, the dictionary grows forever.
- # So every one in a (rare) while, we decide to force an
- # artificial next_generation() and _cleanup_dict().
- self._trigger_automatic_cleanup += 1
- if self._trigger_automatic_cleanup > 20000:
- self._trigger_automatic_cleanup = 0
- memmgr.next_generation(do_cleanups_now=False)
- _cleanup_dict()
- #
- self._trigger_automatic_cleanup = 0
- self._jitcell_dict = jitcell_dict # for tests
- memmgr.record_jitcell_dict(_cleanup_dict)
- else:
- def _maybe_cleanup_dict():
- pass
- #
def get_jitcell(build, *greenargs):
try:
cell = jitcell_dict[greenargs]
except KeyError:
if not build:
return None
- _maybe_cleanup_dict()
- cell = self._new_jitcell()
+ cell = JitCell()
jitcell_dict[greenargs] = cell
return cell
return get_jitcell
@@ -549,10 +464,6 @@
get_jitcell_at_ptr = self.jitdriver_sd._get_jitcell_at_ptr
set_jitcell_at_ptr = self.jitdriver_sd._set_jitcell_at_ptr
lltohlhack = {}
- # note that there is no equivalent of record_jitcell_dict()
- # in the case of custom getters. We assume that the interpreter
- # stores the JitCells on some objects that can go away by GC,
- # like the PyCode objects in PyPy.
#
def get_jitcell(build, *greenargs):
fn = support.maybe_on_top_of_llinterp(rtyper, get_jitcell_at_ptr)
@@ -574,7 +485,7 @@
if not build:
return cell
if cell is None:
- cell = self._new_jitcell()
+ cell = JitCell()
# <hacks>
if we_are_translated():
cellref = cast_object_to_ptr(BASEJITCELL, cell)
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -395,7 +395,6 @@
'retrace_limit': 5,
'max_retrace_guards': 15,
'enable_opts': 'all',
- 'decay_halflife': 40,
}
unroll_parameters = unrolling_iterable(PARAMETERS.items())
DEFAULT = object()
More information about the pypy-commit
mailing list