bpo-40512: Store pointer to interpreter state in a thread local variable#29228
bpo-40512: Store pointer to interpreter state in a thread local variable#29228markshannon wants to merge 11 commits intopython:mainfrom
Conversation
1be2ad9 to
ada883d
Compare
|
🤖 New build scheduled with the buildbot fleet by @markshannon for commit ada883d6b97bb072ef8465b71671ef9db101c7ae 🤖 If you want to schedule another build, you need to add the ":hammer: test-with-buildbots" label again. |
|
Build failures look like the usual suspects. |
ada883d to
f22036b
Compare
| pid_t pid; | ||
|
|
||
| if (_PyInterpreterState_GET() != PyInterpreterState_Main()) { | ||
| if (PyInterpreterState_Get() != PyInterpreterState_Main()) { |
There was a problem hiding this comment.
| if (PyInterpreterState_Get() != PyInterpreterState_Main()) { | |
| PyInterpreterState *interp = PyInterpreterState_Get(); | |
| if (!_Py_IsMainInterpreter(interp)) { |
There was a problem hiding this comment.
It is too easy to overlook the ! when making this change. Using the comparison operator makes it clearer that we are checking that interp is not the main interpreter.
Both @ericsnowcurrently and I have made this mistake recently.
|
@vstinner Any comments? |
|
The old approach had a NULL check and |
Sorry, I don't have the bandwidth to review this change :-( |
| } | ||
|
|
||
| #ifdef _Py_THREAD_LOCAL | ||
| extern _Py_THREAD_LOCAL PyInterpreterState *_py_current_interpreter; |
There was a problem hiding this comment.
Why the current interpreter and not the current PyThreadState?
There was a problem hiding this comment.
Two reasons.
- I though this would add the most value, as we need the interpreter state to get to freelists which are performance critical.
- We already pass the threadstate as an argument to a lot of functions, so I wanted to verify this approach before rewriting all that code.
There was a problem hiding this comment.
Would it make sense to do both? (They are both hot in different situations.) What is the cost to the number of thread-local variables?
| { | ||
| if (encoding == NULL || encoding == Py_None) { | ||
| PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| PyInterpreterState *interp = PyInterpreterState_Get(); |
There was a problem hiding this comment.
Why the switch to PyInterpreterState_Get()?
There was a problem hiding this comment.
Modules cannot access a thread-local directly because they are dynamically loaded. It is a loader, rather a language, limitation, I think.
There was a problem hiding this comment.
That's good to know. Thanks for explaining. This might not be obvious to maintainers. Would you mind adding a short comment next to the declaration of _py_current_interpreter noting the constraint?
Also, this doesn't affect builtin modules, right? Aren't some of the modules updated here builtin modules?
|
I'm dropping this as there are a few reasons why passing the interpreter state explicitly make sense.
|
A more future proof way to handle interpreter state. 1% faster as well.
https://bugs.python.org/issue40512