-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
gh-135871: Fix needless spinning in _PyMutex 8000 _LockTimed (timeout==0) #135872
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
This comment was marked as resolved.
This comment was marked as resolved.
94f04f5
to
88e8a1c
Compare
This comment was marked as duplicate.
This comment was marked as duplicate.
88e8a1c
to
45811fd
Compare
This comment was marked as duplicate.
This comment was marked as duplicate.
…==0) * Move the timeout == 0 guard outside the else so a non-blocking call returns immediately after a failed CAS instead of entering the spin loop. * Reload v on every spin iteration, allowing timed/blocking callers to notice an unlock promptly. No-GIL builds now honor the semantics of non-blocking attempts and avoid wasted CPU; GIL builds are unaffected (MAX_SPIN_COUNT == 0).
45811fd
to
7296a7d
Compare
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.
Please don't force-push, we squash at the end.
Misc/NEWS.d/next/Core and Builtins/2025-06-23-18-08-32.gh-issue-135871.50C528.rst
Outdated
Show resolved
Hide resolved
(Sorry Antoine, hit the wrong button!) |
Misc/NEWS.d/next/Core_and_Builtins/2025-06-23-18-08-32.gh-issue-135871.50C528.rst
Outdated
Show resolved
Hide resolved
Python/lock.c
Outdated
@@ -89,6 +89,7 @@ _PyMutex_LockTimed(PyMutex *m, PyTime_t timeout, _PyLockFlags flags) | |||
// Spin for a bit. | |||
_Py_yield(); | |||
spin_count++; | |||
v = _Py_atomic_load_uint8_relaxed(&m->_bits); |
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 looks like it fixes a logic bug but it also hurts performance
See Tools/lockbench/lockbench.py
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.
thanks for the review! I'm convinced, this line reduces throughput on my machine by something like 40% for 8 threads. I think changing else if
to if
still makes sense though. I updated the 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.
LGTM
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.
LGTM
Let's investigate (and fix) the missing load separately
Misc/NEWS.d/next/Core_and_Builtins/2025-06-23-18-08-32.gh-issue-135871.50C528.rst
Outdated
Show resolved
Hide resolved
…e-135871.50C528.rst
Thanks @jtibbertsma for the PR, and @colesbury for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13, 3.14. |
…ongh-135872) The free threading build could spin unnecessarily on `_Py_yield()` if the initial compare and swap failed. (cherry picked from commit cbfaf41) Co-authored-by: Joseph Tibbertsma <josephtibbertsma@gmail.com>
Sorry, @jtibbertsma and @colesbury, I could not cleanly backport this to
|
GH-135946 is a backport of this pull request to the 3.14 branch. |
GH-135946 is a backport of this pull request to the 3.14 branch. |
pythongh-135872) The free threading build could spin unnecessarily on `_Py_yield()` if the initial compare and swap failed. (cherry picked from commit cbfaf41) Co-authored-by: Joseph Tibbertsma <josephtibbertsma@gmail.com>
GH-135947 is a backport of this pull request to the 3.13 branch. |
GH-135947 is a backport of this pull request to the 3.13 branch. |
Reload v on every spin iteration, allowing timed/blocking callers to notice an unlock promptly.No-GIL builds now honor the semantics of non-blocking attempts and avoid wasted CPU; GIL builds are unaffected (MAX_SPIN_COUNT == 0).
_PyMutex_LockTimed
spins and may fail unnecessarily in no-GIL builds #135871