Author: Armin Rigo <[email protected]>
Branch:
Changeset: r79880:5348f162bc84
Date: 2015-09-28 13:22 +0200
http://bitbucket.org/pypy/pypy/changeset/5348f162bc84/
Log: Another performance boost to the common case of zip().
diff --git a/pypy/module/__builtin__/app_functional.py
b/pypy/module/__builtin__/app_functional.py
--- a/pypy/module/__builtin__/app_functional.py
+++ b/pypy/module/__builtin__/app_functional.py
@@ -5,6 +5,7 @@
from __future__ import with_statement
import operator
from __pypy__ import resizelist_hint, newlist_hint
+from __pypy__ import specialized_zip_2_lists
# ____________________________________________________________
@@ -217,11 +218,16 @@
in length to the length of the shortest argument sequence."""
l = len(sequences)
if l == 2:
+ # A very fast path if the two sequences are lists
+ seq0 = sequences[0]
+ seq1 = sequences[1]
+ try:
+ return specialized_zip_2_lists(seq0, seq1)
+ except TypeError:
+ pass
# This is functionally the same as the code below, but more
# efficient because it unrolls the loops over 'sequences'.
# Only for two arguments, which is the most common case.
- seq0 = sequences[0]
- seq1 = sequences[1]
iter0 = iter(seq0)
iter1 = iter(seq1)
hint = min(100000000, # max 100M
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -83,6 +83,7 @@
'newdict' : 'interp_dict.newdict',
'reversed_dict' : 'interp_dict.reversed_dict',
'strategy' : 'interp_magic.strategy', # dict,set,list
+ 'specialized_zip_2_lists' : 'interp_magic.specialized_zip_2_lists',
'set_debug' : 'interp_magic.set_debug',
'locals_to_fast' : 'interp_magic.locals_to_fast',
'save_module_content_for_future_reload':
diff --git a/pypy/module/__pypy__/interp_magic.py
b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -147,3 +147,7 @@
@unwrap_spec(w_module=MixedModule)
def save_module_content_for_future_reload(space, w_module):
w_module.save_module_content_for_future_reload()
+
+def specialized_zip_2_lists(space, w_list1, w_list2):
+ from pypy.objspace.std.specialisedtupleobject import
specialized_zip_2_lists
+ return specialized_zip_2_lists(space, w_list1, w_list2)
diff --git a/pypy/objspace/std/specialisedtupleobject.py
b/pypy/objspace/std/specialisedtupleobject.py
--- a/pypy/objspace/std/specialisedtupleobject.py
+++ b/pypy/objspace/std/specialisedtupleobject.py
@@ -1,7 +1,7 @@
from pypy.interpreter.error import OperationError
from pypy.objspace.std.tupleobject import W_AbstractTupleObject
from pypy.objspace.std.util import negate
-from rpython.rlib.objectmodel import compute_hash
+from rpython.rlib.objectmodel import compute_hash, specialize
from rpython.rlib.rarithmetic import intmask
from rpython.rlib.unroll import unrolling_iterable
from rpython.tool.sourcetools import func_with_new_name
@@ -146,3 +146,64 @@
return Cls_oo(space, w_arg1, w_arg2)
else:
raise NotSpecialised
+
+# --------------------------------------------------
+# Special code based on list strategies to implement zip(),
+# here with two list arguments only. This builds a zipped
+# list that differs from what the app-level code would build:
+# if the source lists contain sometimes ints/floats and
+# sometimes not, here we will use uniformly 'Cls_oo' instead
+# of using 'Cls_ii' or 'Cls_ff' for the elements that match.
+# This is a trade-off, but it looks like a good idea to keep
+# the list uniform for the JIT---not to mention, it is much
+# faster to move the decision out of the loop.
+
[email protected](1)
+def _build_zipped_spec(space, Cls, lst1, lst2):
+ length = min(len(lst1), len(lst2))
+ return [Cls(space, space.wrap(lst1[i]),
+ space.wrap(lst2[i])) for i in range(length)]
+
+def _build_zipped_spec_oo(space, w_list1, w_list2):
+ strat1 = w_list1.strategy
+ strat2 = w_list2.strategy
+ length = min(strat1.length(w_list1), strat2.length(w_list2))
+ return [Cls_oo(space, strat1.getitem(w_list1, i),
+ strat2.getitem(w_list2, i)) for i in range(length)]
+
+def _build_zipped_unspec(space, w_list1, w_list2):
+ strat1 = w_list1.strategy
+ strat2 = w_list2.strategy
+ length = min(strat1.length(w_list1), strat2.length(w_list2))
+ return [space.newtuple([strat1.getitem(w_list1, i),
+ strat2.getitem(w_list2, i)]) for i in
range(length)]
+
+def specialized_zip_2_lists(space, w_list1, w_list2):
+ from pypy.objspace.std.listobject import W_ListObject
+ if (not isinstance(w_list1, W_ListObject) or
+ not isinstance(w_list2, W_ListObject)):
+ raise OperationError(space.w_TypeError,
+ space.wrap("expected two lists"))
+
+ if space.config.objspace.std.withspecialisedtuple:
+ intlist1 = w_list1.getitems_int()
+ if intlist1 is not None:
+ intlist2 = w_list2.getitems_int()
+ if intlist2 is not None:
+ lst_w = _build_zipped_spec(space, Cls_ii, intlist1, intlist2)
+ return space.newlist(lst_w)
+ else:
+ floatlist1 = w_list1.getitems_float()
+ if floatlist1 is not None:
+ floatlist2 = w_list2.getitems_float()
+ if floatlist2 is not None:
+ lst_w = _build_zipped_spec(space, Cls_ff, floatlist1,
+ floatlist2)
+ return space.newlist(lst_w)
+
+ lst_w = _build_zipped_spec_oo(space, w_list1, w_list2)
+ return space.newlist(lst_w)
+
+ else:
+ lst_w = _build_zipped_unspec(space, w_list1, w_list2)
+ return space.newlist(lst_w)
diff --git a/pypy/objspace/std/test/test_tupleobject.py
b/pypy/objspace/std/test/test_tupleobject.py
--- a/pypy/objspace/std/test/test_tupleobject.py
+++ b/pypy/objspace/std/test/test_tupleobject.py
@@ -407,3 +407,21 @@
assert (() != object()) is True
assert ((1,) != object()) is True
assert ((1, 2) != object()) is True
+
+ def test_zip_two_lists(self):
+ try:
+ from __pypy__ import specialized_zip_2_lists
+ except ImportError:
+ specialized_zip_2_lists = zip
+ raises(TypeError, specialized_zip_2_lists, [], ())
+ raises(TypeError, specialized_zip_2_lists, (), [])
+ assert specialized_zip_2_lists([], []) == [
+ ]
+ assert specialized_zip_2_lists([2, 3], []) == [
+ ]
+ assert specialized_zip_2_lists([2, 3], [4, 5, 6]) == [
+ (2, 4), (3, 5)]
+ assert specialized_zip_2_lists([4.1, 3.6, 7.2], [2.3, 4.8]) == [
+ (4.1, 2.3), (3.6, 4.8)]
+ assert specialized_zip_2_lists(["foo", "bar"], [6, 2]) == [
+ ("foo", 6), ("bar", 2)]
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit