Author: Carl Friedrich Bolz <cfb...@gmx.de> Branch: value-profiling Changeset: r79032:4c1c11cfc6a9 Date: 2015-08-18 11:43 +0200 http://bitbucket.org/pypy/pypy/changeset/4c1c11cfc6a9/
Log: for local variables, only track the type to make the interpreter less bad diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -50,22 +50,15 @@ kwargname = varnames[argcount] if code.co_flags & CO_VARKEYWORDS else None return Signature(argnames, varargname, kwargname) -class ValueProf(valueprof.ValueProf): - def is_int(self, w_obj): - from pypy.objspace.std.intobject import W_IntObject - return type(w_obj) is W_IntObject - - def get_int_val(self, w_obj): - from pypy.objspace.std.intobject import W_IntObject - assert isinstance(w_obj, W_IntObject) - return w_obj.intval +class KnownTypesVersion(object): + pass class PyCode(eval.Code): "CPython-style code objects." _immutable_ = True _immutable_fields_ = ["co_consts_w[*]", "co_names_w[*]", "co_varnames[*]", "co_freevars[*]", "co_cellvars[*]", - "_args_as_cellvars[*]", "vprofs[*]"] + "_args_as_cellvars[*]", "_known_types_version?"] def __init__(self, space, argcount, nlocals, stacksize, flags, code, consts, names, varnames, filename, @@ -95,7 +88,13 @@ self._signature = cpython_code_signature(self) self._initialize() self._init_ready() - self.vprofs = [ValueProf('%s %s' % (self.co_name, self.co_varnames[i])) for i in range(self.co_nlocals)] + # a list of either None, W_Root, or a subclass thereof + # None means "have not seen a value in that local variable yet + # W_Root can be anything + # otherwise it's the precise class of *all* values ever stored in that + # local + self._known_types = [None] * self.co_nlocals + self._known_types_version = KnownTypesVersion() def _initialize(self): if self.co_cellvars: @@ -140,6 +139,21 @@ def _init_ready(self): "This is a hook for the vmprof module, which overrides this method." + def _get_known_type(self, varindex): + # somewhat subtle: + if not jit.we_are_jitted(): + return self._known_types[varindex] + return self._get_known_type_elidable(varindex, self._known_types_version) + + @jit.elidable + def _get_known_type_elidable(self, varindex, version): + assert version is self._known_types_version + return self._known_types[varindex] + + def _update_known_type(self, varindex, cls): + self._known_types[varindex] = cls + self._known_types_version = KnownTypesVersion() + def _cleanup_(self): if (self.magic == cpython_magic and '__pypy__' not in sys.builtin_module_names): diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -4,7 +4,7 @@ from rpython.rlib import jit from rpython.rlib.debug import make_sure_not_resized, check_nonneg from rpython.rlib.jit import hint, we_are_jitted -from rpython.rlib.objectmodel import we_are_translated, instantiate +from rpython.rlib.objectmodel import we_are_translated, instantiate, specialize from rpython.rlib.rarithmetic import intmask, r_uint from rpython.tool.pairtype import extendabletype @@ -146,36 +146,38 @@ return cell def _getlocal(self, varindex): - from pypy.objspace.std.intobject import W_IntObject - # some careful logic there - if we_are_jitted(): - vprof = self.getcode().vprofs[varindex] - if vprof.can_fold_read_int(): - return W_IntObject(vprof.read_constant_int()) - elif vprof.can_fold_read_obj(): - w_res = vprof.try_read_constant_obj() - if w_res is not None: - return w_res w_res = self.locals_cells_stack_w[varindex] if we_are_jitted(): - vprof = self.getcode().vprofs[varindex] - if vprof.class_is_known(): - jit.record_exact_class(w_res, vprof.read_constant_cls()) + cls = self.getcode()._get_known_type(varindex) + if cls is not None and cls is not W_Root: + jit.record_exact_class(w_res, cls) return w_res - def _setlocal(self, varindex, value): - self._value_profile_local(varindex, value) + @specialize.arg(3) + def _setlocal(self, varindex, value, can_be_None=True): + self._see_write(varindex, value, can_be_None) self.locals_cells_stack_w[varindex] = value - def _value_profile_local(self, varindex, value): - from pypy.objspace.std.intobject import W_IntObject - vprof = self.getcode().vprofs[varindex] - vprof.see_write(value) + @specialize.arg(3) + def _see_write(self, varindex, value, can_be_None=True): + cls = self.getcode()._get_known_type(varindex) + if cls is W_Root: + return + if can_be_None and value is None: + new_cls = W_Root + else: + new_cls = value.__class__ + if cls is not None: + if new_cls is not cls: + new_cls = W_Root + else: + return + self.getcode()._update_known_type(varindex, new_cls) @jit.unroll_safe def _all_locals_changed(self): - for i, vprof in enumerate(self.getcode().vprofs): - vprof.see_write(self.locals_cells_stack_w[i]) + for i in range(self.getcode().co_nlocals): + self._see_write(i, self.locals_cells_stack_w[i]) def mark_as_escaped(self): """ diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -505,7 +505,7 @@ def STORE_FAST(self, varindex, next_instr): w_newvalue = self.popvalue() assert w_newvalue is not None - self._setlocal(varindex, w_newvalue) + self._setlocal(varindex, w_newvalue, can_be_None=False) def getfreevarname(self, index): freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars diff --git a/pypy/interpreter/test/test_pyframe.py b/pypy/interpreter/test/test_pyframe.py --- a/pypy/interpreter/test/test_pyframe.py +++ b/pypy/interpreter/test/test_pyframe.py @@ -537,15 +537,29 @@ sys.settrace(None) assert res == 10 -class TestValueProf(object): - def test_argument_is_constant(self): +class TestLocalTypeProfiling(object): + def test_argument_is_constant_type(self): + from pypy.objspace.std.intobject import W_IntObject + from pypy.interpreter.baseobjspace import W_Root space = self.space w_f = space.appexec([], """(): def f(x): y = x + 1 return f""") + v1 = w_f.code._known_types_version + assert w_f.code._known_types == [None] * 2 space.call_function(w_f, space.wrap(1)) - assert len(w_f.code.vprofs) == 2 - assert w_f.code.vprofs[0].can_fold_read_int() - assert w_f.code.vprofs[1].can_fold_read_int() + v2 = w_f.code._known_types_version + assert v2 is not v1 + assert w_f.code._known_types == [W_IntObject] * 2 + space.call_function(w_f, space.wrap(2)) + v3 = w_f.code._known_types_version + assert v3 is v2 + assert w_f.code._known_types == [W_IntObject] * 2 + + space.call_function(w_f, space.wrap(1.1)) + v4 = w_f.code._known_types_version + assert v4 is not v3 + assert w_f.code._known_types == [W_Root] * 2 + _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit