]> granicus.if.org Git - python/commitdiff
*EXPERIMENTAL* speedup of slot_sq_item. This sped up the following
authorGuido van Rossum <guido@python.org>
Wed, 3 Oct 2001 12:09:30 +0000 (12:09 +0000)
committerGuido van Rossum <guido@python.org>
Wed, 3 Oct 2001 12:09:30 +0000 (12:09 +0000)
test dramatically:

    class T(tuple): __dynamic__ = 1
    t = T(range(1000))
    for i in range(1000): tt = tuple(t)

The speedup was about 5x compared to the previous state of CVS (1.7
vs. 8.8, in arbitrary time units).  But it's still more than twice as
slow as as the same test with __dynamic__ = 0 (0.8).

I'm not sure that I really want to go through the trouble of this kind
of speedup for every slot.  Even doing it just for the most popular
slots will be a major effort (the new slot_sq_item is 40+ lines, while
the old one was one line with a powerful macro -- unfortunately the
speedup comes from expanding the macro and doing things in a way
specific to the slot signature).

An alternative that I'm currently considering is sketched in PLAN.txt:
trap setattr on type objects.  But this will require keeping track of
all derived types using weak references.

Include/descrobject.h
Objects/descrobject.c
Objects/typeobject.c

index 1671cebe1bfae4ac5eff557aa9fac661c79ee13e..b79c2faacc87ff5a2fed6d540638b11c7024abfa 100644 (file)
@@ -20,6 +20,40 @@ struct wrapperbase {
        char *doc;
 };
 
+/* Various kinds of descriptor objects */
+
+#define PyDescr_COMMON \
+       PyObject_HEAD \
+       PyTypeObject *d_type; \
+       PyObject *d_name
+
+typedef struct {
+       PyDescr_COMMON;
+} PyDescrObject;
+
+typedef struct {
+       PyDescr_COMMON;
+       PyMethodDef *d_method;
+} PyMethodDescrObject;
+
+typedef struct {
+       PyDescr_COMMON;
+       struct PyMemberDef *d_member;
+} PyMemberDescrObject;
+
+typedef struct {
+       PyDescr_COMMON;
+       PyGetSetDef *d_getset;
+} PyGetSetDescrObject;
+
+typedef struct {
+       PyDescr_COMMON;
+       struct wrapperbase *d_base;
+       void *d_wrapped; /* This can be any function pointer */
+} PyWrapperDescrObject;
+
+extern DL_IMPORT(PyTypeObject) PyWrapperDescr_Type;
+
 extern DL_IMPORT(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *);
 extern DL_IMPORT(PyObject *) PyDescr_NewMember(PyTypeObject *,
                                               struct PyMemberDef *);
index 3a6590226a27d6c904a34716ae44f004eac338ad..1d525daf98f6c9eff533c215cbeeb9642d02e2c3 100644 (file)
@@ -3,38 +3,6 @@
 #include "Python.h"
 #include "structmember.h" /* Why is this not included in Python.h? */
 
-/* Various kinds of descriptor objects */
-
-#define COMMON \
-       PyObject_HEAD \
-       PyTypeObject *d_type; \
-       PyObject *d_name
-
-typedef struct {
-       COMMON;
-} PyDescrObject;
-
-typedef struct {
-       COMMON;
-       PyMethodDef *d_method;
-} PyMethodDescrObject;
-
-typedef struct {
-       COMMON;
-       PyMemberDef *d_member;
-} PyMemberDescrObject;
-
-typedef struct {
-       COMMON;
-       PyGetSetDef *d_getset;
-} PyGetSetDescrObject;
-
-typedef struct {
-       COMMON;
-       struct wrapperbase *d_base;
-       void *d_wrapped; /* This can be any function pointer */
-} PyWrapperDescrObject;
-
 static void
 descr_dealloc(PyDescrObject *descr)
 {
@@ -481,7 +449,7 @@ static PyTypeObject PyGetSetDescr_Type = {
        (descrsetfunc)getset_set,               /* tp_descr_set */
 };
 
-static PyTypeObject PyWrapperDescr_Type = {
+PyTypeObject PyWrapperDescr_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,
        "wrapper_descriptor",
index a681d337c54ed82fdad1064f2a5f67c4fdf3d3c1..d9769455d962e07c86b305944ed049c4fb928008 100644 (file)
@@ -2113,12 +2113,16 @@ wrap_sq_item(PyObject *self, PyObject *args, void *wrapped)
        PyObject *arg;
        int i;
 
-       if (!PyArg_ParseTuple(args, "O", &arg))
-               return NULL;
-       i = getindex(self, arg);
-       if (i == -1 && PyErr_Occurred())
-               return NULL;
-       return (*func)(self, i);
+       if (PyTuple_GET_SIZE(args) == 1) {
+               arg = PyTuple_GET_ITEM(args, 0);
+               i = getindex(self, arg);
+               if (i == -1 && PyErr_Occurred())
+                       return NULL;
+               return (*func)(self, i);
+       }
+       PyArg_ParseTuple(args, "O", &arg);
+       assert(PyErr_Occurred());
+       return NULL;
 }
 
 static struct wrapperbase tab_getitem_int[] = {
@@ -2825,7 +2829,57 @@ slot_sq_length(PyObject *self)
 
 SLOT1(slot_sq_concat, "__add__", PyObject *, "O")
 SLOT1(slot_sq_repeat, "__mul__", int, "i")
-SLOT1(slot_sq_item, "__getitem__", int, "i")
+
+/* Super-optimized version of slot_sq_item.
+   Other slots could do the same... */
+static PyObject *
+slot_sq_item(PyObject *self, int i)
+{
+       static PyObject *getitem_str;
+       PyObject *func, *args = NULL, *ival = NULL, *retval = NULL;
+       descrgetfunc f;
+
+       if (getitem_str == NULL) {
+               getitem_str = PyString_InternFromString("__getitem__");
+               if (getitem_str == NULL)
+                       return NULL;
+       }
+       func = _PyType_Lookup(self->ob_type, getitem_str);
+       if (func != NULL) {
+               if (func->ob_type == &PyWrapperDescr_Type) {
+                       PyWrapperDescrObject *wrapper =
+                               (PyWrapperDescrObject *)func;
+                       if (wrapper->d_base->wrapper == wrap_sq_item) {
+                               intargfunc f;
+                               f = (intargfunc)(wrapper->d_wrapped);
+                               return f(self, i);
+                       }
+               }
+               if ((f = func->ob_type->tp_descr_get) == NULL)
+                       Py_INCREF(func);
+               else
+                       func = f(func, self, (PyObject *)(self->ob_type));
+               ival = PyInt_FromLong(i);
+               if (ival != NULL) {
+                       args = PyTuple_New(1);
+                       if (args != NULL) {
+                               PyTuple_SET_ITEM(args, 0, ival);
+                               retval = PyObject_Call(func, args, NULL);
+                               Py_XDECREF(args);
+                               Py_XDECREF(func);
+                               return retval;
+                       }
+               }
+       }
+       else {
+               PyErr_SetObject(PyExc_AttributeError, getitem_str);
+       }
+       Py_XDECREF(args);
+       Py_XDECREF(ival);
+       Py_XDECREF(func);
+       return NULL;
+}
+
 SLOT2(slot_sq_slice, "__getslice__", int, int, "ii")
 
 static int