-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
bpo-37207: Use PEP 590 vectorcall to speed up range(), list() and dict() by about 30% #13930
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Objects/dictobject.c
Outdated
@@ -3286,6 +3286,56 @@ dict_init(PyObject *self, PyObject *args, PyObject *kwds) | |||
return dict_update_common(self, args, kwds, "dict"); | |||
} | |||
|
|||
static PyObject * | |||
dict_vectorcall( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there should be a newline right after the (
.
Objects/call.c
Outdated
@@ -1320,6 +1320,10 @@ _PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, | |||
return 0; | |||
} | |||
|
|||
if (PyArg_ValidateKeywordArguments(kwargs) == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change may or may not make sense, but in any case I think that it needs to be justified individually and a test added, preferably on a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment in Include/cpython/abstract.h
says that _PyStack_UnpackDict
does not check the type of keyword arguments. So this change is inconsistent with that. If you think that this should be changed, please open a separate issue explaining the rationale for this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The additional validation should have been in PyVectorcall_Call
which does need to do validation. I've moved it there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think that it's better to move that change to a different PR with rationale explained for this change.
Do you have an idea why this speeds up those calls that much? I'm just wondering if we could instead try to optimize the existing code path instead of implementing a mostly duplicate code path. |
What are your plans for inheritance of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the overall approach here. However I have various minor comments (some already mentioned):
- I'm not convinced that vectorcall should be used for
dict()
. There was a discussion about usingMETH_FASTCALL
fordict.update()
in bpo-29312 and the conclusion was that it was a bad idea. So either we need to argue that the conclusion on bpo-29312 was wrong or that it doesn't apply to thedict()
constructor. - You should try to minimize duplication of functionality. For example
range_new
andrange_vectorcall
serve essentially the same purpose, so why are there two functions? You could implement both in terms of a common function or implementrange_new
as
static PyObject *
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
if (kw && PyDict_GET_SIZE(kw) != 0) {
PyErr_Format(PyExc_TypeError, "range() takes no keyword arguments");
return NULL;
}
return range_vectorcall(type, _PyTuple_ITEMS(args),
PyTuple_GET_SIZE(args), NULL);
}
- Use
Py_ssize_t
for thenargs
variable. - The change to
PyVectorcall_Call
does not belong here. Please open a separate PR for that. - I'm getting a compiler warning
Objects/rangeobject.c:765:26: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.tp_vectorcall = range_vectorcall
^~~~~~~~~~~~~~~~
Since |
dict and dict.update are different. |
@methane, I don't understand which point you are trying to make. Right now, there is a common implementation of |
I opened https://bugs.python.org/issue37540 for the issue of checking that keyword names are strings. |
Base PR for other PRs that want to play with `type.__call__` such as #13930 and #14589. The author is really @markshannon I just made the PR. https://bugs.python.org/issue37207 Automerge-Triggered-By: @encukou
Base PR for other PRs that want to play with `type.__call__` such as python#13930 and python#14589. The author is really @markshannon I just made the PR. https://bugs.python.org/issue37207 Automerge-Triggered-By: @encukou
…ch previous error messages.
4671080
to
fec6969
Compare
It would make sense to delegate tp_call for |
fec6969
to
c319141
Compare
@@ -5170,6 +5170,11 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) | |||
!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) | |||
{ | |||
type->tp_flags |= _Py_TPFLAGS_HAVE_VECTORCALL; | |||
/* Also inherit tp_vectorcall if tp_call of the | |||
* metaclass is type.__call__ */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* metaclass is type.__call__ */ | |
* metaclass is type.__call__ */ |
if (nargs == 1) { | ||
int err = 0; | ||
PyObject *arg = args[0]; | ||
_Py_IDENTIFIER(keys); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like two same identifiers in single source file.
Please make _Py_IDENTIFIER(keys);
global static variable.
Base PR for other PRs that want to play with `type.__call__` such as python#13930 and python#14589. The author is really @markshannon I just made the PR. https://bugs.python.org/issue37207 Automerge-Triggered-By: @encukou
This PR has 4 relatively independent parts, and all of it seems stuck on one of them. I opened #18464 to get |
This continues the `range()` part of #13930. The complete pull request is stalled on discussions around dicts, but `range()` should not be controversial. (And I plan to open PRs for other parts if this is merged.) On top of Mark's change, I unified `range_new` and `range_vectorcall`, which had a lot of duplicate code. https://bugs.python.org/issue37207
This PR was splitted into multiple smaller PRs which all are now all merged: see https://bugs.python.org/issue37207 |
Base PR for other PRs that want to play with `type.__call__` such as python#13930 and python#14589. The author is really @markshannon I just made the PR. https://bugs.python.org/issue37207 Automerge-Triggered-By: @encukou
https://bugs.python.org/issue37207