-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Optimize GC.AllocateUninitializedArray and use it in StringBuilder #27364
Optimize GC.AllocateUninitializedArray and use it in StringBuilder #27364
Conversation
…ebug.Asserts are checking the behaviour we get in Release
…he small buffers hot path
The
|
BTW the native call path could benefit a lot from https://github.com/dotnet/coreclr/issues/5329, I am going to add a comment there |
@adamsitnik, I don't understand the StringBuilder benchmarks: these all show them getting slower. What am I missing? |
I am sorry when I was hand-editing the path to CoreRun to replace it with "before" and "after" I've introduced a bug ;p Edit: fixed. Thanks for catching the bug! |
Another interesting case would be if an uninitialized allocation is mixed with ordinary allocation. Allocating one object after each array should do it. |
@GrabYourPitchforks @bartonjs Thoughts about this from the security point of view? |
I can't think of anything offhand. As long as there's no way for a caller to observe the uninitialized data, you should be good. For instance, |
I've modified the benchmark to include single object allocation before allocating the array and the threshold grew to 7kb. |
7k - is that with |
In general I'm not a fan of "malloc vs calloc"; but if we have a plethora of tests then we can feel pretty confident that we're never acting on the uninitialized data (either StringBuilder internally or it being returned to callers). |
int |
…As instead of a cast
@jkotas using Before (using cast): After (using Thanks for another great suggestion! |
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 once the CI is green.
… AllocateSzArray is responsible for handling negative size
I've removed following length check from coreclr/src/vm/comutilnative.cpp Line 1134 in 310f715
Because Lines 446 to 447 in ab2f9ca
|
I wanted to use
GC.AllocateUninitializedArray
inStringBuilder
, but it was initially too slow. Calling it for small buffers was causing quite noticeable performance degradation.I've tuned it up to ensure that it does not slow down the
StringBuilder
in "unlucky path" (small arrays) and does improve the perf in "lucky path" (big arrays). It should make this API more profitable to use in other places in the future.Changes:
int
touint
(if (length < 0)
). This changes the behavior of this internal API forlength < 0
- previously the caller would getIndexOutOfRangeException
. Since this is an internal API, I hope it's OK.GC.AllocateUninitializedArray
, move the expensive native call to separate method to not increase the size too much.Micro benchmarks for the GC API:
I've simplified the default BDN output to make it easier to compare the results. In the table below the "Before" is the execution time for
GC.AllocateUninitializedArray
before my changes, in the "After" are with my changes. Thenew T[]
contains the time for calling new operator (to have some base comparison)