[pypy-commit] pypy default: Two new performance tests, with corresponding fixes (likely broken by 749bf9a13d9c)

arigo noreply at buildbot.pypy.org
Fri May 15 20:17:27 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r77342:a1a494787f41
Date: 2015-05-15 20:17 +0200
http://bitbucket.org/pypy/pypy/changeset/a1a494787f41/

Log:	Two new performance tests, with corresponding fixes (likely broken
	by 749bf9a13d9c)

diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py
--- a/pypy/module/_cffi_backend/ccallback.py
+++ b/pypy/module/_cffi_backend/ccallback.py
@@ -1,7 +1,7 @@
 """
 Callbacks.
 """
-import os
+import sys, os
 
 from rpython.rlib import clibffi, rweakref, jit, jit_libffi
 from rpython.rlib.objectmodel import compute_unique_id, keepalive_until_here
@@ -14,6 +14,8 @@
 from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned
 from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid
 
+BIG_ENDIAN = sys.byteorder == 'big'
+
 # ____________________________________________________________
 
 
@@ -147,7 +149,7 @@
             # zero extension: fill the '*result' with zeros, and (on big-
             # endian machines) correct the 'result' pointer to write to
             misc._raw_memclear(ll_res, SIZE_OF_FFI_ARG)
-            if jit_libffi.BIG_ENDIAN:
+            if BIG_ENDIAN:
                 diff = SIZE_OF_FFI_ARG - fresult.size
                 ll_res = rffi.ptradd(ll_res, diff)
     #
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -207,6 +207,88 @@
             guard_no_exception(descr=...)
         """, ignore_ops=['guard_not_invalidated'])
 
+    def test__cffi_call_c_int(self):
+        def main():
+            import os
+            try:
+                import _cffi_backend
+            except ImportError:
+                sys.stderr.write('SKIP: cannot import _cffi_backend\n')
+                return 0
+
+            libc = _cffi_backend.load_library(None)
+            BInt = _cffi_backend.new_primitive_type("int")
+            BClose = _cffi_backend.new_function_type([BInt], BInt)
+            _dup = libc.load_function(BClose, 'dup')
+            i = 0
+            fd0, fd1 = os.pipe()
+            while i < 300:
+                tmp = _dup(fd0)   # ID: cfficall
+                os.close(tmp)
+                i += 1
+            os.close(fd0)
+            os.close(fd1)
+            BLong = _cffi_backend.new_primitive_type("long")
+            return 42
+        #
+        log = self.run(main, [])
+        assert log.result == 42
+        loop, = log.loops_by_filename(self.filepath)
+        if sys.maxint > 2**32:
+            extra = "i98 = int_signext(i97, 4)"
+        else:
+            extra = ""
+        assert loop.match_by_id('cfficall', """
+            p96 = force_token()
+            setfield_gc(p0, p96, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .>)
+            i97 = call_release_gil(91, i59, i50, descr=<Calli 4 i EF=7 OS=62>)
+            guard_not_forced(descr=...)
+            guard_no_exception(descr=...)
+            %s
+        """ % extra, ignore_ops=['guard_not_invalidated'])
+
+    def test__cffi_call_size_t(self):
+        def main():
+            import os
+            try:
+                import _cffi_backend
+            except ImportError:
+                sys.stderr.write('SKIP: cannot import _cffi_backend\n')
+                return 0
+
+            libc = _cffi_backend.load_library(None)
+            BInt = _cffi_backend.new_primitive_type("int")
+            BSizeT = _cffi_backend.new_primitive_type("size_t")
+            BChar = _cffi_backend.new_primitive_type("char")
+            BCharP = _cffi_backend.new_pointer_type(BChar)
+            BWrite = _cffi_backend.new_function_type([BInt, BCharP, BSizeT],
+                                                     BSizeT)  # not signed here!
+            _write = libc.load_function(BWrite, 'write')
+            i = 0
+            fd0, fd1 = os.pipe()
+            buffer = _cffi_backend.newp(BCharP, 'A')
+            while i < 300:
+                tmp = _write(fd1, buffer, 1)   # ID: cfficall
+                assert tmp == 1
+                assert os.read(fd0, 2) == 'A'
+                i += 1
+            os.close(fd0)
+            os.close(fd1)
+            return 42
+        #
+        log = self.run(main, [])
+        assert log.result == 42
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match_by_id('cfficall', """
+            p96 = force_token()
+            setfield_gc(p0, p96, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .>)
+            i97 = call_release_gil(91, i59, i10, i12, 1, descr=<Calli . iii EF=7 OS=62>)
+            guard_not_forced(descr=...)
+            guard_no_exception(descr=...)
+            p98 = call(ConstClass(fromrarith_int__r_uint), i97, descr=<Callr . i EF=4>)
+            guard_no_exception(descr=...)
+        """, ignore_ops=['guard_not_invalidated'])
+
     def test_cffi_call_guard_not_forced_fails(self):
         # this is the test_pypy_c equivalent of
         # rpython/jit/metainterp/test/test_fficall::test_guard_not_forced_fails
diff --git a/rpython/rlib/jit_libffi.py b/rpython/rlib/jit_libffi.py
--- a/rpython/rlib/jit_libffi.py
+++ b/rpython/rlib/jit_libffi.py
@@ -3,8 +3,7 @@
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rlib import clibffi, jit
 from rpython.rlib.rarithmetic import r_longlong, r_singlefloat
-
-BIG_ENDIAN = sys.byteorder == 'big'
+from rpython.rlib.unroll import unrolling_iterable
 
 FFI_CIF = clibffi.FFI_CIFP.TO
 FFI_TYPE = clibffi.FFI_TYPE_P.TO
@@ -114,8 +113,10 @@
     reskind = types.getkind(cif_description.rtype)
     if reskind == 'v':
         jit_ffi_call_impl_void(cif_description, func_addr, exchange_buffer)
-    elif reskind == 'i' or reskind == 'u':
-        _do_ffi_call_int(cif_description, func_addr, exchange_buffer)
+    elif reskind == 'i':
+        _do_ffi_call_sint(cif_description, func_addr, exchange_buffer)
+    elif reskind == 'u':
+        _do_ffi_call_uint(cif_description, func_addr, exchange_buffer)
     elif reskind == 'f':
         _do_ffi_call_float(cif_description, func_addr, exchange_buffer)
     elif reskind == 'L': # L is for longlongs, on 32bit
@@ -132,21 +133,44 @@
         jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer)
 
 
-def _do_ffi_call_int(cif_description, func_addr, exchange_buffer):
+_short_sint_types = unrolling_iterable([rffi.SIGNEDCHAR, rffi.SHORT, rffi.INT])
+_short_uint_types = unrolling_iterable([rffi.UCHAR, rffi.USHORT, rffi.UINT])
+
+def _do_ffi_call_sint(cif_description, func_addr, exchange_buffer):
     result = jit_ffi_call_impl_int(cif_description, func_addr,
                                    exchange_buffer)
-    if BIG_ENDIAN:
-        # Special case: we need to store an integer of 'c_size' bytes
-        # only.  To avoid type-specialization hell, we always store a
-        # full Signed here, but by shifting it to the left on big-endian
-        # we get the result that we want.
-        size = rffi.getintfield(cif_description.rtype, 'c_size')
-        if size < SIZE_OF_SIGNED:
-            result <<= (SIZE_OF_SIGNED - size) * 8
-    llop.raw_store(lltype.Void,
-                   llmemory.cast_ptr_to_adr(exchange_buffer),
-                   cif_description.exchange_result,
-                   result)
+    size = types.getsize(cif_description.rtype)
+    for TP in _short_sint_types:     # short **signed** types
+        if size == rffi.sizeof(TP):
+            llop.raw_store(lltype.Void,
+                           llmemory.cast_ptr_to_adr(exchange_buffer),
+                           cif_description.exchange_result,
+                           rffi.cast(TP, result))
+            break
+    else:
+        # default case: expect a full signed number
+        llop.raw_store(lltype.Void,
+                       llmemory.cast_ptr_to_adr(exchange_buffer),
+                       cif_description.exchange_result,
+                       result)
+
+def _do_ffi_call_uint(cif_description, func_addr, exchange_buffer):
+    result = jit_ffi_call_impl_int(cif_description, func_addr,
+                                   exchange_buffer)
+    size = types.getsize(cif_description.rtype)
+    for TP in _short_uint_types:     # short **unsigned** types
+        if size == rffi.sizeof(TP):
+            llop.raw_store(lltype.Void,
+                           llmemory.cast_ptr_to_adr(exchange_buffer),
+                           cif_description.exchange_result,
+                           rffi.cast(TP, result))
+            break
+    else:
+        # default case: expect a full unsigned number
+        llop.raw_store(lltype.Void,
+                       llmemory.cast_ptr_to_adr(exchange_buffer),
+                       cif_description.exchange_result,
+                       rffi.cast(lltype.Unsigned, result))
 
 def _do_ffi_call_float(cif_description, func_addr, exchange_buffer):
     # a separate function in case the backend doesn't support floats
@@ -284,6 +308,11 @@
 
     @staticmethod
     @jit.elidable
+    def getsize(ffi_type):
+        return rffi.getintfield(ffi_type, 'c_size')
+
+    @staticmethod
+    @jit.elidable
     def is_struct(ffi_type):
         return rffi.getintfield(ffi_type, 'c_type') == FFI_TYPE_STRUCT
 


More information about the pypy-commit mailing list