[pypy-commit] pypy default: Found another reason for slowness of dict.update(): the keys are wrapped
arigo
noreply at buildbot.pypy.org
Tue Jul 8 15:26:37 CEST 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r72387:7f9dca73c7b6
Date: 2014-07-08 13:33 +0200
http://bitbucket.org/pypy/pypy/changeset/7f9dca73c7b6/
Log: Found another reason for slowness of dict.update(): the keys are
wrapped and unwrapped. Fixed, and removed the magic SpecTag too.
diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -3,7 +3,6 @@
from rpython.rlib import jit, rerased, objectmodel
from rpython.rlib.debug import mark_dict_non_null
from rpython.rlib.objectmodel import newlist_hint, r_dict, specialize
-from rpython.rlib.unroll import SpecTag
from rpython.tool.sourcetools import func_renamer, func_with_new_name
from pypy.interpreter.baseobjspace import W_Root
@@ -759,35 +758,51 @@
# this is very similar to the general version, but the difference
# is that it is specialized to call a specific next_item()
iteritems = IterClassItems(self.space, self, w_dict)
- spec = _SPEC1
+ w_key, w_value = iteritems.next_item()
+ if w_key is None:
+ return
+ w_updatedict.setitem(w_key, w_value)
+ w_updatedict.strategy.prepare_update(w_updatedict,
+ w_dict.length() - 1)
while True:
w_key, w_value = iteritems.next_item()
if w_key is None:
+ return
+ w_updatedict.setitem(w_key, w_value)
+ else:
+ iteritems = self.getiteritems(w_dict)
+ if not same_strategy(self, w_updatedict):
+ # Different strategy. Try to copy one item of w_dict
+ for key, value in iteritems:
+ w_key = wrapkey(self.space, key)
+ w_value = wrapvalue(self.space, value)
+ w_updatedict.setitem(w_key, w_value)
break
- w_updatedict.setitem(w_key, w_value)
- if spec is _SPEC1:
- spec = _SPEC2
- w_updatedict.strategy.prepare_update(w_updatedict,
- w_dict.length() - 1)
- else:
- spec = _SPEC1
- iteritems = self.getiteritems(w_dict)
- for key, value in iteritems:
- if spec is not _SPEC3:
- if (setitem_untyped is not None and
- self is w_updatedict.strategy):
- dstorage = w_updatedict.dstorage
- spec = _SPEC3
- else:
+ else:
+ return # w_dict is completely empty, nothing to do
+ count = w_dict.length() - 1
+ w_updatedict.strategy.prepare_update(w_updatedict, count)
+ # If the strategy is still different, continue the slow way
+ if not same_strategy(self, w_updatedict):
+ for key, value in iteritems:
w_key = wrapkey(self.space, key)
w_value = wrapvalue(self.space, value)
w_updatedict.setitem(w_key, w_value)
- if spec is _SPEC3:
- setitem_untyped(self, dstorage, key, value)
- if spec is _SPEC1:
- spec = _SPEC2
- w_updatedict.strategy.prepare_update(w_updatedict,
- w_dict.length() - 1)
+ return # done
+ else:
+ # Same strategy.
+ self.prepare_update(w_updatedict, w_dict.length())
+ #
+ # Use setitem_untyped() to speed up copying without
+ # wrapping/unwrapping the key.
+ assert setitem_untyped is not None
+ dstorage = w_updatedict.dstorage
+ for key, value in iteritems:
+ setitem_untyped(self, dstorage, key, value)
+
+ def same_strategy(self, w_otherdict):
+ return (setitem_untyped is not None and
+ w_otherdict.strategy is self)
dictimpl.iterkeys = iterkeys
dictimpl.itervalues = itervalues
@@ -796,10 +811,6 @@
create_iterator_classes(EmptyDictStrategy)
-_SPEC1 = SpecTag() # first iteration
-_SPEC2 = SpecTag() # all other iteration
-_SPEC3 = SpecTag() # same strategy with setitem_untyped()
-
# concrete subclasses of the above
More information about the pypy-commit
mailing list