Author: Antonio Cuni <anto.c...@gmail.com>
Branch: faster-rstruct-2
Changeset: r91269:196fb3e1e9b3
Date: 2017-05-12 18:19 +0200
http://bitbucket.org/pypy/pypy/changeset/196fb3e1e9b3/

Log:    finally! Add a fastpath for packing ints :)

diff --git a/rpython/rlib/rstruct/standardfmttable.py 
b/rpython/rlib/rstruct/standardfmttable.py
--- a/rpython/rlib/rstruct/standardfmttable.py
+++ b/rpython/rlib/rstruct/standardfmttable.py
@@ -14,9 +14,12 @@
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rlib.buffer import StringBuffer
 from rpython.rlib import rarithmetic
-from rpython.rlib.buffer import CannotRead
+from rpython.rlib.buffer import CannotRead, CannotWrite
 from rpython.rtyper.lltypesystem import rffi
 
+USE_FASTPATH = True    # set to False by some tests
+ALLOW_SLOWPATH = True  # set to False by some tests
+
 native_is_bigendian = struct.pack("=i", 1) == struct.pack(">i", 1)
 native_is_ieee754 = float.__getformat__('double').startswith('IEEE')
 
@@ -65,6 +68,21 @@
     fmtiter.advance(1)
     _pack_string(fmtiter, string, count-1)
 
+@specialize.memo()
+def pack_fastpath(TYPE):
+    @specialize.argtype(0)
+    def do_pack_fastpath(fmtiter, value):
+        size = rffi.sizeof(TYPE)
+        pos = fmtiter.pos
+        if (not USE_FASTPATH or
+            fmtiter.bigendian != native_is_bigendian or
+            pos % size != 0):
+            raise CannotWrite
+        # the following might raise CannotWrite and abort the fastpath
+        fmtiter.result.typed_write(TYPE, fmtiter.pos, value)
+        fmtiter.advance(size)
+    return do_pack_fastpath
+
 def make_float_packer(size):
     def packer(fmtiter):
         fl = fmtiter.accept_float_arg()
@@ -124,6 +142,7 @@
     errormsg = "argument out of range for %d-byte%s integer format" % (size,
                                                                        plural)
     unroll_revrange_size = unrolling_iterable(range(size-1, -1, -1))
+    TYPE = get_rffi_int_type(size, signed)
 
     def pack_int(fmtiter):
         method = getattr(fmtiter, accept_method)
@@ -131,6 +150,14 @@
         if not min <= value <= max:
             raise StructError(errormsg)
         #
+        try:
+            pack_fastpath(TYPE)(fmtiter, value)
+            return
+        except CannotWrite:
+            if not ALLOW_SLOWPATH:
+                # we enter here only in some tests
+                raise ValueError("fastpath not taken :(")
+        #
         pos = fmtiter.pos + size - 1        
         if fmtiter.bigendian:
             for i in unroll_revrange_size:
@@ -148,9 +175,6 @@
 
 # ____________________________________________________________
 
-USE_FASTPATH = True    # set to False by some tests
-ALLOW_SLOWPATH = True  # set to False by some tests
-
 
 @specialize.memo()
 def unpack_fastpath(TYPE):
diff --git a/rpython/rlib/rstruct/test/test_pack.py 
b/rpython/rlib/rstruct/test/test_pack.py
--- a/rpython/rlib/rstruct/test/test_pack.py
+++ b/rpython/rlib/rstruct/test/test_pack.py
@@ -1,4 +1,5 @@
 import pytest
+from rpython.rlib.rarithmetic import r_ulonglong
 from rpython.rlib.rstruct import standardfmttable, nativefmttable
 from rpython.rlib.mutbuffer import MutableStringBuffer
 import struct
@@ -40,6 +41,23 @@
     fmt_prefix = None
     fmttable = None
 
+    USE_FASTPATH = True
+    ALLOW_SLOWPATH = True
+    
+    def setup_method(self, meth):
+        standardfmttable.USE_FASTPATH = self.USE_FASTPATH
+        standardfmttable.ALLOW_SLOWPATH = self.ALLOW_SLOWPATH
+
+    def teardown_method(self, meth):
+        standardfmttable.USE_FASTPATH = True
+        standardfmttable.ALLOW_SLOWPATH = True
+
+    def teardown_method(self, meth):
+        if not hasattr(self.fmttable, 'USE_FASTPATH'):
+            return
+        self.fmttable.USE_FASTPATH = self.orig_use_fastpath
+        self.fmttable.ALLOW_SLOWPATH = self.orig_allow_slowpath
+
     def mypack(self, fmt, value):
         size = struct.calcsize(fmt)
         fake_fmtiter = FakeFormatIter(self.bigendian, size, value)
@@ -69,7 +87,7 @@
         self.check("I", 0x81424344)
         self.check("q", 0x4142434445464748)
         self.check("q", -0x41B2B3B4B5B6B7B8)
-        self.check("Q", 0x8142434445464748)
+        self.check("Q", r_ulonglong(0x8142434445464748))
 
     def test_pack_ieee(self):
         self.check('f', 123.456)
@@ -107,12 +125,22 @@
     fmt_prefix = '<'
     fmttable = standardfmttable.standard_fmttable
 
+class TestPackLittleEndianSlowPath(TestPackLittleEndian):
+    USE_FASTPATH = False
+
 class TestPackBigEndian(BaseTestPack):
     bigendian = True
     fmt_prefix = '>'
     fmttable = standardfmttable.standard_fmttable
 
+class TestPackBigEndianSlowPath(TestPackBigEndian):
+    USE_FASTPATH = False
+
+
 class TestNative(BaseTestPack):
+    # native packing automatically use the proper endianess, so it should
+    # always take the fast path
+    ALLOW_SLOWPATH = False
     bigendian = nativefmttable.native_is_bigendian
     fmt_prefix = '@'
     fmttable = nativefmttable.native_fmttable
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to