Conversation
PyType_Ready() now sets type tp_as_xxx members to a structure filled of NULL if a member is NULL. It avoids checking if tp_as_xxx is NULL in Objects/abstract.c functions.
|
I wrote a patch to run a microbenchmark on PyNumber_Add() with two integers (1+2): Detailsdiff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index eb769294fd2..c388711fdf1 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2879,6 +2879,47 @@ uptime_bsd(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
#endif
+static PyObject*
+bench_add(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ Py_ssize_t loops;
+ if (!PyArg_ParseTuple(args, "n", &loops)) {
+ return NULL;
+ }
+
+ PyObject *one = PyLong_FromLong(1);
+ PyObject *two = PyLong_FromLong(1);
+ assert(one != NULL && two != NULL);
+
+ PyTime_t t1, t2;
+ (void)PyTime_PerfCounterRaw(&t1);
+ PyObject *sum;
+
+#define ADD() \
+ sum = PyNumber_Add(one, two); \
+ if (sum == NULL) { \
+ return NULL; \
+ } \
+ Py_DECREF(sum);
+
+ for (Py_ssize_t i=0; i < loops; i++) {
+ ADD();
+ ADD();
+ ADD();
+ ADD();
+ ADD();
+ ADD();
+ ADD();
+ ADD();
+ ADD();
+ ADD();
+ }
+
+ (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},
@@ -2978,6 +3019,7 @@ static PyMethodDef TestMethods[] = {
#ifdef HAVE_SYSCTLBYNAME
{"uptime_bsd", uptime_bsd, METH_NOARGS},
#endif
+ {"bench_add", bench_add, METH_VARARGS},
{NULL, NULL} /* sentinel */
};
Benchmark: import pyperf
import _testcapi
runner = pyperf.Runner()
runner.bench_time_func('int + int', _testcapi.bench_add)Result: Well... the difference is quite minor. So I'm not sure that the change is worth it. |
|
I also tried adding This work would be easier to do if PyTypeObject structure was opaque, but it's part of the public C API, so it cannot be easily changed :-( We have to keep |
|
The performance impact might be better than you think! See #149180. |
PyType_Ready() now sets type tp_as_xxx members to a structure filled of NULL if a member is NULL. It avoids checking if tp_as_xxx is NULL in Objects/abstract.c functions.