-
Notifications
You must be signed in to change notification settings - Fork 1
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
Avoid macros and static inline functions #18
Comments
See also issue #37: Declare constants as variables, instead of macros. |
I'm not sure why According to https://en.cppreference.com/w/c/language/inline (emphasis mine):
There is a helpful StackOverflow answer about this: So you can have this in a inline returntype
Py_Foo(args)
{
...
} and then in a single extern PyAPI_FUNC(returntype)
Py_Foo(args); |
I'm guessing the (only? by far most common?) use of inline functions in CPython is |
@gvanrossum I think you're right! |
FYI the rationale for using The impact on performance of static inline functions (versus macros) was measured in PEP 670 – Convert macros to functions in the Python C API. |
An alternative is to convert static inline functions to regular functions. So far, I didn't see any conclusive analysis that static inline functions are really faster than regular function calls, especially in third party C extensions. |
I don't want to diminish your work, but I don't see any "rationale" in this discussion, just a number of comments that seem to be talking past each other, and an arbitrary decision from you at the end :-)
I agree that performance claims should generally be backed with benchmark numbers, but I don't think a lot of analysis is required to conclude that Yes, most C extensions might not benefit from inlining of trivial functions such as |
This issue isn't about Py_INCREF() or PyTuple_GET_ITEM(), but more general. I'm not suggesting to convert Py_INCREF() or PyTuple_GET_ITEM() to regular functions. I'm just saying that we should design a guideline to decide which functions are seen as performance critical and should have a faster variant, and which ones don't need that. I don't think that all of the ~1600 C API functions need to have a faster variant (only a small numbers have it right now).
I don't see the point of your remark unless you want to diminish my work. Maybe just omit it next time.
I'm just giving pointers to past discussions if some people want to understand how We can move from |
Message moved to a new issue: Define a public "maximize performance" API and separate it better from the regular "maximize compatibility" API. |
This is derailing the discussion from the subject of this issue ("avoid macros and static inline functions"). Perhaps you should open a separate issue for that guideline? |
Right. I created #45 for my previous message. |
I'm not sure that it's possible if we take in account the name of the static inline function which should also have a good name. The most common case is that the static inline function is used. Using a different name is as annoying as having the opaque function with a different name. The problem is to define a static inline function and a regular function with the same name (in the same header file): PyAPI_FUNC(void) _Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt);
static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) {
#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030d0000
_Py_SetRefcnt(ob, refcnt);
#else
...
#endif // Py_LIMITED_API+0 < 0x030d0000
} If the two functions have the same name: PyAPI_FUNC(void) Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt);
static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { ... } The compiler fails with:
For example, in gdb, currently, I can put a breakpoint on
In Python 3.10, static inline functions had different names than the public C API. For example, Symbols have different use cases:
With your proposed change, all functions implemented as static inline functions must now be referred as their private name: Existing functions implemented as static inline functions and opaque function calls:
|
No. This is what the (C-specific) alias is there for: |
The macro keeps API compatibility: same API name. But at the ABI level, such as names in gdb, _Py_Foo_impl() will be used with such macro. |
These pitfalls would be avoided by switching to non-static |
I wrote python/cpython#112794 which may satisfy all requirements:
Yes, obviously, my implementation uses and abuses macros. But differently that what @encukou proposes, since the static inline function is only renamed if the new This way, C extensions built with the static inline functions continue to use C extensions built with the limited C API version 3.13 and newer use the |
And to compare with @pitrou's suggestion, I wrote an implementation where the regular API and the stable ABI both use |
I must admit I'm not too familiar with (non-static) inline. This reference text is worrying:
It seems that if we make any change to an inline function in a point release, and an extension compiled with new headers is run on older CPython, then:
How does that work in practice? With dynamically loaded libraries? |
So, this can technically only happen if using the stable ABI (limited API), in which case the definition isn't found in the headers, so the definition from the CPython library should be used. |
I think that it's reasonable goal to make sure that it's possible to access any function using The issue title is "Avoid macros and static inline functions". I'm not sure that I understand the title. Do you suggest to convert all macros and static inline functions to regular functions? Your example keeps the static inline and export the function as a regular function. Maybe the title should be updated to clarify the goal, such as "All functions should be exported as proper symbols". |
No, you can build with 3.13.5 and run on 3.13.0.
No. All the
Yes, and explain what “proper” means. For non-function macros there's #37 |
Oh, you're right. I'm not sure what the concrete consequences would be, even in C++. Presumably the compiler wouldn't decompile the implementation from the shared library and say "oh, this is different from the definition in the current compilation unit, so this is UB and I'm allowed to do whatever I want". That said, using
@gpshead Any opinions on this topic? |
Added to the draft in #53. |
All functions should be exported as proper symbols, so they are usable without a C preprocessor/parser.
We expect a lot of exceptions, which should be added as alternatives to proper functions (as per #4).
Macros or static inline functions can override/shadow a function with the same name and behavior. The dance for that is:
Header file:
.c
file:Let's have Argument Clinic generate the boilerplate?
Another exception are C-specific helper macros, like
Py_VISIT
orPy_MIN
. IMO, the docs for these should document the internals clearly enough that people can rewrite them in other languages.Unless they're not useful in other languages (like
Py_UNREACHABLE
orPy_UNUSED
).The text was updated successfully, but these errors were encountered: