-
Notifications
You must be signed in to change notification settings - Fork 785
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
[sdk-metrics] Tags perf improvements #5457
[sdk-metrics] Tags perf improvements #5457
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5457 +/- ##
==========================================
+ Coverage 83.38% 85.43% +2.05%
==========================================
Files 297 289 -8
Lines 12531 12493 -38
==========================================
+ Hits 10449 10674 +225
+ Misses 2082 1819 -263
Flags with carried forward coverage won't be shown. Click here to find out more.
|
@CodeBlanch can you add the code used in the benchmarks for reference as well? |
@cijothomas Added |
Given we are ultra optimized for <=3 tags, and reasonably optimized for 3-7 tags, it'd be nicer to use a tagCount<7 in benchmarks shared, to see more practical gains. Also, if feasible, can you show the existing benchmarks before/after, so as to get a picture of how much this affects overall perf. (hash calc and equals() is significant chunk of overall metrics cost in hot path, so I expect this to be significant. But curios if it is significant enough to show up in normal benchmark runs) |
var cursor = ourKvps.Length; | ||
if (cursor > 0) | ||
{ | ||
ref var ours = ref MemoryMarshal.GetArrayDataReference(ourKvps); |
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.
Is this and the Unsafe.Add
calls vulnerable to garbage collector relocating this array when compacting memory?
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.
AFAIK they are managed pointers meaning the GC is aware of them.
I ran this pattern by @stephentoub a while back. IIRC the answer was it is safe to do so long as you know for sure the array references won't change out from under you and they are indeed the same length.
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.
If done correctly, it's valid. These are managed refs, so if the GC were to move things around, it would also update the values stored in the refs to keep them valid. The concern with code like this is it's easy to accidentally get it wrong, at which point you're subject to all the same kinds of memory safety problems as in languages like C++. As a simple for loop, the JIT would already be eliminating the bounds check on accessing the elements from whichever span was used in the for loop condition, so at best this is only eliminating the other half of the bounds checks. You'll want to be really, really sure it's worth it.
@cijothomas I updated the description to show benchmarks for different number of tags. There aren't any optimizations in Here is a run of Before:
After:
|
@@ -73,7 +74,7 @@ public Tags(KeyValuePair<string, object?>[] keyValuePairs) | |||
} | |||
} | |||
#else | |||
for (int i = 0; i < ourKvps.Length; i++) | |||
for (int i = 0; i < length; i++) |
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.
Don't we want this to use one of the array's length properties? Would it be skipping the bounds check if we use a regular int
?
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.
It does seem to elide using the local ya. Here's a demo: SharpLab
Notice in "ElideTest1" there is call 0x7ff9435f8f40
that is the thing that throws the range check failure. The other two don't have that.
Changes
Tags
hash code computation and equality checksstring.Equals
without passingStringComparison
(seems to inline better)Benchmarks
Code
Merge requirement checklist