diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index 20497ee9301..3f27dfd8195 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -254,7 +254,7 @@ extern PyObject* _PyUnicode_FormatLong(PyObject *, int, int, int); /* Fast equality check when the inputs are known to be exact unicode types and where the hash values are equal (i.e. a very probable match) */ -extern int _PyUnicode_EQ(PyObject *, PyObject *); +PyAPI_FUNC(int) _PyUnicode_EQ(PyObject *, PyObject *); // Equality check. // Export for '_pickle' shared extension. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 5966eb674cf..a2604bfac21 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3329,6 +3329,126 @@ test_critical_sections(PyObject *module, PyObject *Py_UNUSED(args)) Py_RETURN_NONE; } +static PyObject * +bench_eq(PyObject *module, PyObject *args) +{ + extern int _PyUnicode_EQ(PyObject *, PyObject *); + + Py_ssize_t loops; + PyObject *a, *b; + if (!PyArg_ParseTuple(args, "nOO", &loops, &a, &b)) { + return NULL; + } + + PyTime_t t1, t2; + (void)PyTime_PerfCounterRaw(&t1); + + for (Py_ssize_t i=0; i < loops; i++) { + int eq = _PyUnicode_EQ(a, b); + if (eq != 1) { + abort(); + } + } + + (void)PyTime_PerfCounterRaw(&t2); + return PyFloat_FromDouble(PyTime_AsSecondsDouble(t2 - t1)); +} + +static PyObject * +bench__equal(PyObject *module, PyObject *args) +{ + extern int _PyUnicode_Equal(PyObject *, PyObject *); + + Py_ssize_t loops; + PyObject *a, *b; + if (!PyArg_ParseTuple(args, "nOO", &loops, &a, &b)) { + return NULL; + } + + PyTime_t t1, t2; + (void)PyTime_PerfCounterRaw(&t1); + + for (Py_ssize_t i=0; i < loops; i++) { + int eq = _PyUnicode_Equal(a, b); + if (eq != 1) { + abort(); + } + } + + (void)PyTime_PerfCounterRaw(&t2); + return PyFloat_FromDouble(PyTime_AsSecondsDouble(t2 - t1)); +} + +static PyObject * +bench_equal(PyObject *module, PyObject *args) +{ + Py_ssize_t loops; + PyObject *a, *b; + if (!PyArg_ParseTuple(args, "nOO", &loops, &a, &b)) { + return NULL; + } + + PyTime_t t1, t2; + (void)PyTime_PerfCounterRaw(&t1); + + for (Py_ssize_t i=0; i < loops; i++) { + int eq = PyUnicode_Equal(a, b); + if (eq != 1) { + abort(); + } + } + + (void)PyTime_PerfCounterRaw(&t2); + return PyFloat_FromDouble(PyTime_AsSecondsDouble(t2 - t1)); +} + +static PyObject * +bench_compare(PyObject *module, PyObject *args) +{ + Py_ssize_t loops; + PyObject *a, *b; + if (!PyArg_ParseTuple(args, "nOO", &loops, &a, &b)) { + return NULL; + } + + PyTime_t t1, t2; + (void)PyTime_PerfCounterRaw(&t1); + + for (Py_ssize_t i=0; i < loops; i++) { + int eq = PyUnicode_Compare(a, b); + if (eq != 0) { + abort(); + } + } + + (void)PyTime_PerfCounterRaw(&t2); + return PyFloat_FromDouble(PyTime_AsSecondsDouble(t2 - t1)); +} + +static PyObject * +bench_richcmp(PyObject *module, PyObject *args) +{ + Py_ssize_t loops; + PyObject *a, *b; + if (!PyArg_ParseTuple(args, "nOO", &loops, &a, &b)) { + return NULL; + } + + PyTime_t t1, t2; + (void)PyTime_PerfCounterRaw(&t1); + + for (Py_ssize_t i=0; i < loops; i++) { + PyObject *res = PyUnicode_RichCompare(a, b, Py_EQ); + if (!PyObject_IsTrue(res)) { + abort(); + } + Py_DECREF(res); + } + + (void)PyTime_PerfCounterRaw(&t2); + return PyFloat_FromDouble(PyTime_AsSecondsDouble(t2 - t1)); +} + static PyMethodDef TestMethods[] = { {"set_errno", set_errno, METH_VARARGS}, {"test_config", test_config, METH_NOARGS}, @@ -3469,6 +3589,11 @@ static PyMethodDef TestMethods[] = { {"test_weakref_capi", test_weakref_capi, METH_NOARGS}, {"function_set_warning", function_set_warning, METH_NOARGS}, {"test_critical_sections", test_critical_sections, METH_NOARGS}, + {"bench_eq", bench_eq, METH_VARARGS}, + {"bench__equal", bench__equal, METH_VARARGS}, + {"bench_equal", bench_equal, METH_VARARGS}, + {"bench_compare", bench_compare, METH_VARARGS}, + {"bench_richcmp", bench_richcmp, METH_VARARGS}, {NULL, NULL} /* sentinel */ };