On 8/15/06, "Martin v. Löwis" <[EMAIL PROTECTED]> wrote:
That penalty is already paid today. Much code dealing with ints has a type test whether it's an int or a long. If int and long become subtypes of each other or of some abstract type, performance will decrease even more because a subtype test is quite expensive if the object is neither int nor long (it has to traverse the entire base type hierarchy to find out its not inherited from int).
I was playing around with a little patch to avoid that penalty. It doesn't take any additional memory, just a handful of bits we aren't using. :-) For the more common builtin types, it stores whether it's a subclass in tp_flags, so there's no function call necessary and it's a constant time operation. It was faster when doing simple stuff. Haven't thought much whether this is really worthwhile or not. n
Index: Include/stringobject.h =================================================================== --- Include/stringobject.h (revision 51237) +++ Include/stringobject.h (working copy) @@ -55,8 +55,9 @@ PyAPI_DATA(PyTypeObject) PyBaseString_Type; PyAPI_DATA(PyTypeObject) PyString_Type; -#define PyString_Check(op) PyObject_TypeCheck(op, &PyString_Type) #define PyString_CheckExact(op) ((op)->ob_type == &PyString_Type) +#define PyString_Check(op) (PyString_CheckExact(op) || \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_STRING_SUBCLASS)) PyAPI_FUNC(PyObject *) PyString_FromStringAndSize(const char *, Py_ssize_t); PyAPI_FUNC(PyObject *) PyString_FromString(const char *); Index: Include/dictobject.h =================================================================== --- Include/dictobject.h (revision 51237) +++ Include/dictobject.h (working copy) @@ -90,8 +90,9 @@ PyAPI_DATA(PyTypeObject) PyDict_Type; -#define PyDict_Check(op) PyObject_TypeCheck(op, &PyDict_Type) #define PyDict_CheckExact(op) ((op)->ob_type == &PyDict_Type) +#define PyDict_Check(op) (PyDict_CheckExact(op) || \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_DICT_SUBCLASS)) PyAPI_FUNC(PyObject *) PyDict_New(void); PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key); Index: Include/unicodeobject.h =================================================================== --- Include/unicodeobject.h (revision 51237) +++ Include/unicodeobject.h (working copy) @@ -390,8 +390,9 @@ PyAPI_DATA(PyTypeObject) PyUnicode_Type; -#define PyUnicode_Check(op) PyObject_TypeCheck(op, &PyUnicode_Type) #define PyUnicode_CheckExact(op) ((op)->ob_type == &PyUnicode_Type) +#define PyUnicode_Check(op) (PyUnicode_CheckExact(op) || \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_UNICODE_SUBCLASS)) /* Fast access macros */ #define PyUnicode_GET_SIZE(op) \ Index: Include/intobject.h =================================================================== --- Include/intobject.h (revision 51237) +++ Include/intobject.h (working copy) @@ -27,8 +27,9 @@ PyAPI_DATA(PyTypeObject) PyInt_Type; -#define PyInt_Check(op) PyObject_TypeCheck(op, &PyInt_Type) #define PyInt_CheckExact(op) ((op)->ob_type == &PyInt_Type) +#define PyInt_Check(op) (PyInt_CheckExact(op) || \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_INT_SUBCLASS)) PyAPI_FUNC(PyObject *) PyInt_FromString(char*, char**, int); #ifdef Py_USING_UNICODE Index: Include/listobject.h =================================================================== --- Include/listobject.h (revision 51237) +++ Include/listobject.h (working copy) @@ -40,8 +40,9 @@ PyAPI_DATA(PyTypeObject) PyList_Type; -#define PyList_Check(op) PyObject_TypeCheck(op, &PyList_Type) #define PyList_CheckExact(op) ((op)->ob_type == &PyList_Type) +#define PyList_Check(op) (PyList_CheckExact(op) || \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_LIST_SUBCLASS)) PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size); PyAPI_FUNC(Py_ssize_t) PyList_Size(PyObject *); Index: Include/object.h =================================================================== --- Include/object.h (revision 51237) +++ Include/object.h (working copy) @@ -517,6 +517,18 @@ /* Objects support nb_index in PyNumberMethods */ #define Py_TPFLAGS_HAVE_INDEX (1L<<17) +/* These flags are used to determine if a type is a subclass. */ +/* Uses bits 30-27. */ +#define Py_TPFLAGS_FAST_SUBCLASS_MASK (0x78000000) +#define Py_TPFLAGS_FAST_SUBCLASS (1L<<27) +#define Py_TPFLAGS_INT_SUBCLASS (Py_TPFLAGS_FAST_SUBCLASS | 0x70000000) +#define Py_TPFLAGS_LONG_SUBCLASS (Py_TPFLAGS_FAST_SUBCLASS | 0x60000000) +#define Py_TPFLAGS_LIST_SUBCLASS (Py_TPFLAGS_FAST_SUBCLASS | 0x50000000) +#define Py_TPFLAGS_TUPLE_SUBCLASS (Py_TPFLAGS_FAST_SUBCLASS | 0x40000000) +#define Py_TPFLAGS_STRING_SUBCLASS (Py_TPFLAGS_FAST_SUBCLASS | 0x30000000) +#define Py_TPFLAGS_UNICODE_SUBCLASS (Py_TPFLAGS_FAST_SUBCLASS | 0x20000000) +#define Py_TPFLAGS_DICT_SUBCLASS (Py_TPFLAGS_FAST_SUBCLASS | 0x10000000) + #define Py_TPFLAGS_DEFAULT ( \ Py_TPFLAGS_HAVE_GETCHARBUFFER | \ Py_TPFLAGS_HAVE_SEQUENCE_IN | \ @@ -530,6 +542,7 @@ 0) #define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0) +#define PyType_FastSubclass(t,f) (((t)->tp_flags & Py_TPFLAGS_FAST_SUBCLASS_MASK) == (f)) /* Index: Include/tupleobject.h =================================================================== --- Include/tupleobject.h (revision 51237) +++ Include/tupleobject.h (working copy) @@ -33,8 +33,9 @@ PyAPI_DATA(PyTypeObject) PyTuple_Type; -#define PyTuple_Check(op) PyObject_TypeCheck(op, &PyTuple_Type) #define PyTuple_CheckExact(op) ((op)->ob_type == &PyTuple_Type) +#define PyTuple_Check(op) (PyTuple_CheckExact(op) || \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_TUPLE_SUBCLASS)) PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size); PyAPI_FUNC(Py_ssize_t) PyTuple_Size(PyObject *); Index: Include/longobject.h =================================================================== --- Include/longobject.h (revision 51237) +++ Include/longobject.h (working copy) @@ -11,8 +11,9 @@ PyAPI_DATA(PyTypeObject) PyLong_Type; -#define PyLong_Check(op) PyObject_TypeCheck(op, &PyLong_Type) #define PyLong_CheckExact(op) ((op)->ob_type == &PyLong_Type) +#define PyLong_Check(op) (PyLong_CheckExact(op) || \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_LONG_SUBCLASS)) PyAPI_FUNC(PyObject *) PyLong_FromLong(long); PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long); Index: Objects/typeobject.c =================================================================== --- Objects/typeobject.c (revision 51237) +++ Objects/typeobject.c (working copy) @@ -2956,6 +2956,22 @@ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) { COPYVAL(tp_dictoffset); } + + /* Setup fast subclass flags */ + if (PyType_IsSubtype(base, &PyInt_Type)) + type->tp_flags |= Py_TPFLAGS_INT_SUBCLASS; + else if (PyType_IsSubtype(base, &PyLong_Type)) + type->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS; + else if (PyType_IsSubtype(base, &PyString_Type)) + type->tp_flags |= Py_TPFLAGS_STRING_SUBCLASS; + else if (PyType_IsSubtype(base, &PyUnicode_Type)) + type->tp_flags |= Py_TPFLAGS_UNICODE_SUBCLASS; + else if (PyType_IsSubtype(base, &PyTuple_Type)) + type->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS; + else if (PyType_IsSubtype(base, &PyList_Type)) + type->tp_flags |= Py_TPFLAGS_LIST_SUBCLASS; + else if (PyType_IsSubtype(base, &PyDict_Type)) + type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS; } static void
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com