[pypy-commit] pypy cpyext-faster-arg-passing: speed up passing some objects to C
cfbolz
pypy.commits at gmail.com
Thu Dec 14 14:00:59 EST 2017
Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: cpyext-faster-arg-passing
Changeset: r93421:85fea167b9ea
Date: 2017-12-14 20:00 +0100
http://bitbucket.org/pypy/pypy/changeset/85fea167b9ea/
Log: speed up passing some objects to C
specifically, passing the instances of classes defined in C is
faster, because the Python-version of these instances stores a
reference to the pyobj directly in the instance.
(this should be generalized and extended to more cases)
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -21,6 +21,14 @@
#________________________________________________________
# type description
+class W_BaseCPyObject(W_ObjectObject):
+ """ A subclass of W_ObjectObject that has one field for directly storing
+ the link from the w_obj to the cpy ref. This is only used for C-defined
+ types. """
+
+ _cpy_ref = lltype.nullptr(PyObject.TO)
+
+
class BaseCpyTypedescr(object):
basestruct = PyObject.TO
W_BaseObject = W_ObjectObject
@@ -66,8 +74,12 @@
def realize(self, space, obj):
w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
+ assert isinstance(w_type, W_TypeObject)
try:
- w_obj = space.allocate_instance(self.W_BaseObject, w_type)
+ if w_type.flag_cpytype:
+ w_obj = space.allocate_instance(W_BaseCPyObject, w_type)
+ else:
+ w_obj = space.allocate_instance(self.W_BaseObject, w_type)
except OperationError as e:
if e.match(space, space.w_TypeError):
raise oefmt(space.w_SystemError,
@@ -76,6 +88,9 @@
w_type)
raise
track_reference(space, obj, w_obj)
+ if w_type.flag_cpytype:
+ assert isinstance(w_obj, W_BaseCPyObject)
+ w_obj._cpy_ref = obj
return w_obj
typedescr_cache = {}
@@ -186,7 +201,7 @@
Ties together a PyObject and an interpreter object.
The PyObject's refcnt is increased by REFCNT_FROM_PYPY.
The reference in 'py_obj' is not stolen! Remember to decref()
- it is you need to.
+ it if you need to.
"""
# XXX looks like a PyObject_GC_TRACK
assert py_obj.c_ob_refcnt < rawrefcount.REFCNT_FROM_PYPY
@@ -237,7 +252,7 @@
@jit.dont_look_inside
def as_pyobj(space, w_obj, w_userdata=None, immortal=False):
"""
- Returns a 'PyObject *' representing the given intepreter object.
+ Returns a 'PyObject *' representing the given interpreter object.
This doesn't give a new reference, but the returned 'PyObject *'
is valid at least as long as 'w_obj' is. **To be safe, you should
use keepalive_until_here(w_obj) some time later.** In case of
@@ -245,7 +260,12 @@
"""
assert not is_pyobj(w_obj)
if w_obj is not None:
- py_obj = rawrefcount.from_obj(PyObject, w_obj)
+ if isinstance(w_obj, W_BaseCPyObject):
+ py_obj = w_obj._cpy_ref
+ if not we_are_translated():
+ assert py_obj == rawrefcount.from_obj(PyObject, w_obj)
+ else:
+ py_obj = rawrefcount.from_obj(PyObject, w_obj)
if not py_obj:
py_obj = create_ref(space, w_obj, w_userdata, immortal=immortal)
#
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -3,10 +3,21 @@
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.module.cpyext.api import generic_cpy_call
-from pypy.module.cpyext.pyobject import make_ref, from_ref, decref
+from pypy.module.cpyext.pyobject import make_ref, from_ref, decref, as_pyobj
from pypy.module.cpyext.typeobject import PyTypeObjectPtr
class AppTestTypeObject(AppTestCpythonExtensionBase):
+
+ def setup_class(cls):
+ AppTestCpythonExtensionBase.setup_class.im_func(cls)
+ def _check_uses_shortcut(w_inst):
+ from pypy.module.cpyext.pyobject import W_BaseCPyObject
+ assert isinstance(w_inst, W_BaseCPyObject)
+ assert w_inst._cpy_ref
+ assert as_pyobj(cls.space, w_inst) == w_inst._cpy_ref
+ cls.w__check_uses_shortcut = cls.space.wrap(
+ gateway.interp2app(_check_uses_shortcut))
+
def test_typeobject(self):
import sys
module = self.import_module(name='foo')
@@ -157,6 +168,14 @@
assert fuu2(u"abc").baz().escape()
raises(TypeError, module.fooType.object_member.__get__, 1)
+ def test_shortcut(self):
+ # test that instances of classes that are defined in C become an
+ # instance of W_BaseCPyObject and thus can be converted faster back to
+ # their pyobj, because they store a pointer to it directly.
+ module = self.import_module(name='foo')
+ obj = module.fooType()
+ self._check_uses_shortcut(obj)
+
def test_multiple_inheritance1(self):
module = self.import_module(name='foo')
obj = module.UnicodeSubtype(u'xyz')
More information about the pypy-commit
mailing list