mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
Optimize slots: avoid temporary PyMethodObject
Issue #29507: Optimize slots calling Python methods. For Python methods, get the unbound Python function and prepend arguments with self, rather than calling the descriptor which creates a temporary PyMethodObject. Add a new _PyObject_FastCall_Prepend() function used to call the unbound Python method with self. It avoids the creation of a temporary tuple to pass positional arguments. Avoiding temporary PyMethodObject and avoiding temporary tuple makes Python slots up to 1.46x faster. Microbenchmark on a __getitem__() method implemented in Python: Median +- std dev: 121 ns +- 5 ns -> 82.8 ns +- 1.0 ns: 1.46x faster (-31%) Co-Authored-by: INADA Naoki <songofacandy@gmail.com>
This commit is contained in:
parent
c42c65574d
commit
516b98161a
3 changed files with 166 additions and 58 deletions
|
@ -2367,6 +2367,41 @@ _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs,
|
|||
/* Positional arguments are obj followed by args:
|
||||
call callable(obj, *args, **kwargs) */
|
||||
PyObject *
|
||||
_PyObject_FastCall_Prepend(PyObject *callable,
|
||||
PyObject *obj, PyObject **args, Py_ssize_t nargs)
|
||||
{
|
||||
PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
|
||||
PyObject **args2;
|
||||
PyObject *result;
|
||||
|
||||
nargs++;
|
||||
if (nargs <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
|
||||
args2 = small_stack;
|
||||
}
|
||||
else {
|
||||
args2 = PyMem_Malloc(nargs * sizeof(PyObject *));
|
||||
if (args2 == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* use borrowed references */
|
||||
args2[0] = obj;
|
||||
memcpy(&args2[1],
|
||||
args,
|
||||
(nargs - 1)* sizeof(PyObject *));
|
||||
|
||||
result = _PyObject_FastCall(callable, args2, nargs);
|
||||
if (args2 != small_stack) {
|
||||
PyMem_Free(args2);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Call callable(obj, *args, **kwargs). */
|
||||
PyObject *
|
||||
_PyObject_Call_Prepend(PyObject *callable,
|
||||
PyObject *obj, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue