GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — Performance regression from PyMutex spin-loop reloading in free-threaded builds · Issue #157914 · python/cpython Closed Closed Copy link Labels 3.15bugs and security fixesbugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error DescriptionBug reportBug 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:import time from threading import Thread THREADS = 4 KEYS = tuple(f"key-{i}" for i in range(16)) UPDATES_PER_THREAD = 1_000_000 def update_dict(): d = dict.fromkeys(KEYS, 0) def worker(): keys = KEYS h = d for update in range(UPDATES_PER_THREAD): key = keys[update % len(keys)] h[key] = update workers = [Thread(target=worker) for _ in range(THREADS)] for w in workers: w.start() for w in workers: w.join() started = time.perf_counter() update_dict() took = time.perf_counter() - started print(f"{took:.3f}s") Which outputs 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 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 PRsActivity
MetadataMetadataAssigneesLabels3.15bugs and security fixesbugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error ProjectsMilestoneRelationshipsDevelopmentIssue actions |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |