Antoine Pitrou <[EMAIL PROTECTED]> added the comment:

Hello,

> You may get better timings if you more the types-are-equal test inside
> the types-i-know test.

I get no discernable difference.

> In general, I'm not too keen on adding this kind of dispatch code to
> ceval.c.  It saves the time spent in PyObject_RichCompare() trying to
> figure out where to delegate the work.

Some minimal type testing is necessary if we want to implement the
identity-implies-equality optimization for some types without breaking
the fact that e.g. NaN != NaN. This optimization is important when
dealing with e.g. interned strings. There could be a special flag in the
type structure signaling that the optimization is safe.

I'm attaching a patch which reduces the additional dispatch to a
minimum. The speedup on pybench is smaller, but there is no significant
slowdown for "other" comparisons.

Test                             minimum run-time        average  run-time
                                 this    other   diff    this    other   diff
-------------------------------------------------------------------------------
                 CompareFloats:   176ms   173ms   +1.9%   180ms   175ms   +3.2%
         CompareFloatsIntegers:   237ms   234ms   +1.0%   251ms   240ms   +4.6%
               CompareIntegers:   266ms   276ms   -3.6%   266ms   278ms   -4.3%
        CompareInternedStrings:   160ms   261ms  -38.6%   161ms   261ms  -38.4%
                  CompareLongs:   156ms   166ms   -6.1%   156ms   167ms   -7.1%
                CompareStrings:   167ms   172ms   -2.9%   170ms   173ms   -1.9%
-------------------------------------------------------------------------------
Totals:                          1161ms  1281ms   -9.4%  1184ms  1295ms   -8.6%

Added file: http://bugs.python.org/file12021/cmps4.patch

_______________________________________
Python tracker <[EMAIL PROTECTED]>
<http://bugs.python.org/issue3106>
_______________________________________
diff -r c8ad1bd796f0 Objects/longobject.c
--- a/Objects/longobject.c      Sun Nov 16 19:33:53 2008 +0100
+++ b/Objects/longobject.c      Sun Nov 16 21:28:08 2008 +0100
@@ -2209,37 +2209,60 @@
 static int
 long_compare(PyLongObject *a, PyLongObject *b)
 {
-       Py_ssize_t sign;
-
-       if (Py_SIZE(a) != Py_SIZE(b)) {
-               if (ABS(Py_SIZE(a)) == 0 && ABS(Py_SIZE(b)) == 0)
-                       sign = 0;
-               else
-                       sign = Py_SIZE(a) - Py_SIZE(b);
+       Py_ssize_t sa = Py_SIZE(a), sb = Py_SIZE(b), i;
+       if (sa != sb) {
+               return sa > sb ? 1 : -1;
        }
-       else {
-               Py_ssize_t i = ABS(Py_SIZE(a));
-               while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
-                       ;
-               if (i < 0)
-                       sign = 0;
-               else {
-                       sign = (int)a->ob_digit[i] - (int)b->ob_digit[i];
-                       if (Py_SIZE(a) < 0)
-                               sign = -sign;
+       i = ABS(sa);
+       while (--i >= 0) {
+               digit ad = a->ob_digit[i], bd = b->ob_digit[i];
+               if (ad != bd) {
+                       if (sa < 0)
+                               return ad < bd ? 1 : -1;
+                       else
+                               return ad > bd ? 1 : -1;
                }
        }
-       return sign < 0 ? -1 : sign > 0 ? 1 : 0;
+       return 0;
 }
+
+#define TEST_COND(cond) \
+       ((cond) ? Py_True : Py_False)
 
 static PyObject *
 long_richcompare(PyObject *self, PyObject *other, int op)
 {
-       PyObject *result;
+       int cmp;
+       PyObject *v;
        CHECK_BINOP(self, other);
-       result = Py_CmpToRich(op, long_compare((PyLongObject*)self, 
-                                              (PyLongObject*)other));
-       return result;
+       cmp = long_compare((PyLongObject*)self,
+                                              (PyLongObject*)other);
+       /* Convert the return value to a Boolean */
+       switch (op) {
+       case Py_EQ:
+               v = TEST_COND(cmp == 0);
+               break;
+       case Py_NE:
+               v = TEST_COND(cmp != 0);
+               break;
+       case Py_LE:
+               v = TEST_COND(cmp <= 0);
+               break;
+       case Py_GE:
+               v = TEST_COND(cmp >= 0);
+               break;
+       case Py_LT:
+               v = TEST_COND(cmp == -1);
+               break;
+       case Py_GT:
+               v = TEST_COND(cmp == 1);
+               break;
+       default:
+               PyErr_BadArgument();
+               return NULL;
+       }
+       Py_INCREF(v);
+       return v;
 }
 
 static long
diff -r c8ad1bd796f0 Objects/unicodeobject.c
--- a/Objects/unicodeobject.c   Sun Nov 16 19:33:53 2008 +0100
+++ b/Objects/unicodeobject.c   Sun Nov 16 21:28:08 2008 +0100
@@ -6508,81 +6508,62 @@
     return 0;
 }
 
+
+#define TEST_COND(cond) \
+       ((cond) ? Py_True : Py_False)
+
 PyObject *PyUnicode_RichCompare(PyObject *left,
                                 PyObject *right,
                                 int op)
 {
     int result;
 
-    result = PyUnicode_Compare(left, right);
-    if (result == -1 && PyErr_Occurred())
-        goto onError;
-
-    /* Convert the return value to a Boolean */
-    switch (op) {
-    case Py_EQ:
-        result = (result == 0);
-        break;
-    case Py_NE:
-        result = (result != 0);
-        break;
-    case Py_LE:
-        result = (result <= 0);
-        break;
-    case Py_GE:
-        result = (result >= 0);
-        break;
-    case Py_LT:
-        result = (result == -1);
-        break;
-    case Py_GT:
-        result = (result == 1);
-        break;
-    }
-    return PyBool_FromLong(result);
-
- onError:
-
-    /* Standard case
-
-       Type errors mean that PyUnicode_FromObject() could not convert
-       one of the arguments (usually the right hand side) to Unicode,
-       ie. we can't handle the comparison request. However, it is
-       possible that the other object knows a comparison method, which
-       is why we return Py_NotImplemented to give the other object a
-       chance.
-
-    */
-    if (PyErr_ExceptionMatches(PyExc_TypeError)) {
-        PyErr_Clear();
-        Py_INCREF(Py_NotImplemented);
-        return Py_NotImplemented;
-    }
-    if (op != Py_EQ && op != Py_NE)
-        return NULL;
-
-    /* Equality comparison.
-
-       This is a special case: we silence any PyExc_UnicodeDecodeError
-       and instead turn it into a PyErr_UnicodeWarning.
-
-    */
-    if (!PyErr_ExceptionMatches(PyExc_UnicodeDecodeError))
-        return NULL;
-    PyErr_Clear();
-    if (PyErr_WarnEx(PyExc_UnicodeWarning, 
-                     (op == Py_EQ) ? 
-                     "equal comparison "
-                     "failed to convert both arguments to str - "
-                     "interpreting them as being unequal"
-                     :
-                     "Unicode unequal comparison "
-                     "failed to convert both arguments to str - "
-                     "interpreting them as being unequal",
-                     1) < 0)
-        return NULL;
-    result = (op == Py_NE);
-    return PyBool_FromLong(result);
+    if (PyUnicode_Check(left) && PyUnicode_Check(right)) {
+               PyObject *v;
+               if (((PyUnicodeObject *) left)->length !=
+                       ((PyUnicodeObject *) right)->length) {
+                       if (op == Py_EQ) {
+                               Py_INCREF(Py_False);
+                               return Py_False;
+                       }
+                       if (op == Py_NE) {
+                               Py_INCREF(Py_True);
+                               return Py_True;
+                       }
+               }
+        result = unicode_compare((PyUnicodeObject *)left,
+                               (PyUnicodeObject *)right);
+
+               /* Convert the return value to a Boolean */
+               switch (op) {
+               case Py_EQ:
+                       v = TEST_COND(result == 0);
+                       break;
+               case Py_NE:
+                       v = TEST_COND(result != 0);
+                       break;
+               case Py_LE:
+                       v = TEST_COND(result <= 0);
+                       break;
+               case Py_GE:
+                       v = TEST_COND(result >= 0);
+                       break;
+               case Py_LT:
+                       v = TEST_COND(result == -1);
+                       break;
+               case Py_GT:
+                       v = TEST_COND(result == 1);
+                       break;
+               default:
+                       PyErr_BadArgument();
+                       return NULL;
+               }
+               Py_INCREF(v);
+               return v;
+       }
+
+       Py_INCREF(Py_NotImplemented);
+       return Py_NotImplemented;
 }
 
 int PyUnicode_Contains(PyObject *container,
diff -r c8ad1bd796f0 Python/ceval.c
--- a/Python/ceval.c    Sun Nov 16 19:33:53 2008 +0100
+++ b/Python/ceval.c    Sun Nov 16 21:28:08 2008 +0100
@@ -3782,6 +3782,28 @@
                }
                res = PyErr_GivenExceptionMatches(v, w);
                break;
+       case PyCmp_EQ:
+       case PyCmp_LE:
+       case PyCmp_GE:
+               res = 1;
+       case PyCmp_NE:
+       case PyCmp_LT:
+       case PyCmp_GT:
+               if (v == w) {
+                       /* Optimization note: we must be careful, a few objects 
can be
+                          unequal to themselves (e.g. float("nan")). To keep 
things
+                          simple and fast, we only check for common builtin 
types.
+                          The check could be replaced by a dedicated flag in 
the
+                          type structure. */
+                       if (PyType_FastSubclass(Py_TYPE(v), 
Py_TPFLAGS_LONG_SUBCLASS
+                                       | Py_TPFLAGS_LIST_SUBCLASS
+                                       | Py_TPFLAGS_BYTES_SUBCLASS
+                                       | Py_TPFLAGS_TUPLE_SUBCLASS
+                                       | Py_TPFLAGS_INT_SUBCLASS
+                                       | Py_TPFLAGS_UNICODE_SUBCLASS
+                                       | Py_TPFLAGS_DICT_SUBCLASS))
+                               break;
+               }
        default:
                return PyObject_RichCompare(v, w, op);
        }
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to