Repository navigation
Improve ConcurrentStack.TryPopRange performance under contention. #134306
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -586,6 +586,8 @@ private int TryPopCore(int count, out Node? poppedHead) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Node? head; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Node next; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int backoff = 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int shift = Numerics.BitOperations.Log2(int.MaxValue / (uint)count); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int checkHeadMask = (1 << shift) - 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there some rationale behind this formula? If I am reading this correctly, these additional checks are only going to kick for count >30k. For example, when count = 10_000, checkHeadMask is going to be 131071 and so we won't execute any additional checks. So it is surprising that you are able to measure an improvement for 10_000.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right — for The rationale was to make the check interval adaptive to Regarding the improvements observed at smaller counts (like 10,000), the repeated runs don't show a consistent benefit, so I don't consider them meaningful evidence for the heuristic:
Baseline (Before):
I don't consider small-count improvements meaningful evidence for the heuristic; the main value of this PR lies in large ranges under high contention, where stopping stale traversals can prevent severe performance degradation. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while (true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| head = _head; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -605,6 +607,13 @@ private int TryPopCore(int count, out Node? poppedHead) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (; nodesCount < count && next._next != null; nodesCount++) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| next = next._next; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ((nodesCount & checkHeadMask) == 0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (head != _head) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+610
to
+614
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Valid feedback
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did some additional experiments around skipping the CAS after detecting that
For 100,000+, skipping the CAS caused a substantial regression under contention, reaching seconds per iteration. These cases also take significantly longer to benchmark. @tannergooding, I'd be interested in your thoughts on this, and whether there is a way to avoid the CAS instruction in this path. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Try to swap the new head. If we succeed, break out of the loop. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.