Repository navigation
Performance regression from PyMutex spin-loop reloading in free-threaded builds #157914
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Sep 21, 2026 ping @colesbury @mpage
- addedinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
on Sep 21, 2026 I don't see any harm in reverting the original PR.
Could you open the revert PR?
cc @hugovkReacted by Daniele ParmeggianiIIUC, the related issue only occurs during an unnecessary operation, so reverting the original PR should not reintroduce any significant issue.
Going to open it tomorrow. Quick question in the meantime, since the news entry got merged in here, my guess is I should delete it from there, correct?
Reacted by Donghee NaThe devguide says:
Most changes made to the codebase deserve an entry in Misc/NEWS.d, except for the following:
- ...
- changes that already have a
NEWSentry - reverts that have not yet been included in any formal release (including alpha and beta releases)
For the last two, note the following:
-
If a change is reverted prior to release, then the corresponding entry is simply removed. Otherwise, a new entry must be added noting that the change has been reverted (for example, when a feature is released in an alpha and then cut prior to the first beta).
-
If a change is a fix (or other adjustment) to an earlier unreleased change and the original
NEWSentry remains valid, then no additional entry is needed.
#146064 was released in v3.15.0a8, so leave the existing
NEWSentry, and add a new one for this revert.Reacted by Daniele Parmeggiani and Donghee Na
Bug report
Bug description:
While testing out the new releases of 3.15, I have noticed that this PR, which I authored, introduced a significant performance regression and I would advise to revert it.
I had found this issue while testing a program like this one:
Which outputs
0.507sonmainand0.260swith the revert, on an M4 Max. Note that essentially this is the case where several threads try to write into a shared dictionary, so I wouldn't necessarily call this artificial.The patch changes the acquisition path of PyMutex to reload the lock state while in the spinning phase, before parking the thread after a number of failed attempts. Prior to my change, the lock state was never reloaded during the spinning phase, which is arguably a bad thing for a spinlock to do. Regardless, reloading is a tradeoff between increasing the contention on the lock state due to the read and promptness of acquisition. Under certain workloads, the tradeoff works in favor of reloading and in others it doesn't, hindering the acquisition rate.
This was always known, but I didn't realize the extent with which this impacts certain scenarios. From what I could observe by running the
lockbench.pyscript under a wide variety of parameter values, the greatest improvement is around 3x more throughput, while the greatest slowdown is around 6x less throughput. I ran this comparison sweep with Codex betweenmainandmainwith commitdaa159f98b3689ae6a587bfb978b931762f9dbc9reverted. (See attached pdf for the results.)I have tried for the past week to work on a patch that would keep the speedups and cope with the slowdowns, but I couldn't find a way to do it.
I believe the mistake made with this patch was looking for a mutex performance improvement without a good enough set of benchmarks, though that would be a big problem to tackle in and of itself. It was thus difficult to see how this would have impacted related code like the one shown. One way to deal with this in the future would be to bruteforce it and try many possible parameter sets for lockbench, as I did in writing this. (Which is easier than coming up with a good set of benchmarks for PyMutex.)
My gut feeling is to follow the principle of least surprise and revert the patch, at least for now. We may evaluate alternative implementations later, possibly once we have broader benchmark coverage.
Reverting would arguably re-open the associated issue, as it pertains this patch, though I'm not sure if it can be fixed given how much reloading hurts performance in some cases. Note that the non-blocking call problem mentioned in the issue was fixed separately and reverting the PR above would not impact it.
CPython versions tested on:
CPython main branch
Operating systems tested on:
macOS
Linked PRs
PyMutex_LockTimed(gh-146064)" #158082PyMutex_LockTimed(gh-146064)" (gh-158082) #158290