-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
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
PyType_IsSubtype is doing excessive work in the common case #89860
Comments
Based on real world profiling data we collected, a vast amount of In the common case, the arguments to this call are identical, but the implementation still walks the MRO. By returning early for identical types, the common case can be optimized with a non-trivial performance gain. |
Interesting. It seems like several call sites already check the equality case: ---- setobject.h: ---- #define PyFrozenSet_Check(ob) \
(Py_IS_TYPE(ob, &PyFrozenSet_Type) || \
PyType_IsSubtype(Py_TYPE(ob), &PyFrozenSet_Type)) ---- object.h: ---- static inline int _PyObject_TypeCheck(PyObject *ob, PyTypeObject *type) {
return Py_IS_TYPE(ob, type) || PyType_IsSubtype(Py_TYPE(ob), type);
}
#define PyObject_TypeCheck(ob, type) _PyObject_TypeCheck(_PyObject_CAST(ob), type) Perhaps it would be better to use PyObject_TypeCheck where applicable (such as in the type_call function you mention, and in abstract.c's binary_op1()). |
Dennis, you mean something like this? itamaro@92d46b2 sure, that would preempt the |
Dennis, can PyFrozenSet_Check and _PyObject_TypeCheck get rid of Py_IS_TYPE invocation then, so PyType_IsSubtype becomes the only source of truth here? |
The PyObject_TypeCheck() macro is used in performance critical cases. If it is not the case the PyType_IsSubtype() function can be used. Adding yet check in PyType_IsSubtype() will slow down more performance sensitive cases in which PyObject_TypeCheck() is used and speed up less performance sensitive cases. So there is no reason to add it. |
Not Dennis, but these changes looks good. As Serhiy mentioned, we can replace the hot callsites with PyObject_TypeCheck without slowing down PyType_IsSubtype. |
thanks for the feedback & discussion, I submitted a new PR |
Creating a new type takes microseconds, and using PyObject_TypeCheck() instead of PyType_IsSubtype() can save nanoseconds. So, while this replacement looks harmless, its effect can hardly be measured even in microbenchmarks. |
thanks for the feedback Serhiy! repeating my response from the PR here as well (not sure what's the proper etiquette.. :-) ) note that this code path is not for creating new types (which is slow as you say), but for creating new instances (which is quite fast). I ran some synthetic benchmarks with this change and without it (on an opt build with PGO and LTO), and the gain is measurable: build from main (commit acc89db which is the base commit for this PR):
build with this change applied (commit 2362bf6):
also worth noting that the previous approach (GH-29380) was implemented on the Instagram Server production workload in Meta/Facebook/Instagram (choose your favorite) and resulted measurable perf gain of around 0.2% |
Thank you for your contribution Itamar. |
Summary: Upstream issue: python/cpython#89860 Upstream PR: python/cpython#29392 This also ports D14351113 + D32175230 (7b5bc58) from 3.8 to 3.10 Reviewed By: alexmalyshev Differential Revision: D42229775 fbshipit-source-id: 0bd735a
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: