-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Remove double array allocation in SemanticTokens #74271
Remove double array allocation in SemanticTokens #74271
Conversation
This code was calling ArrayBuilder.ToArray, which would always allocate a new array as a result. Additionally, the arraybuilder itself would end up being large enough that it wouldn't end up going back into the pool. Thus, two large array were allocated on many calls into this method. There really is no need for this method to use ArrayBuilder, as the code that ends up owning the resultant array doesn't attempt to put it back into a pool. This shows up as about 0.5% of allocation in devenv in the customer profile I'm looking at, half of which should be removed by this change.
There's an issue here, didn't notice that currentClassifiedSpanIndex was modified inside the loop, outside of normal loop incrementing |
Switched back to a pool, as the array size isn't known before the loop. Instead of ArrayBuilder, which doesn't pool array bigger than 128 elements, used a separate ObjectPool<List> |
@dotnet/roslyn-ide -- ptal |
@@ -243,23 +245,31 @@ private static void ConvertMultiLineToSingleLineSpans(SourceText text, Segmented | |||
|
|||
var tokenTypeMap = SemanticTokensSchema.GetSchema(supportsVisualStudioExtensions).TokenTypeMap; | |||
|
|||
using var _ = ArrayBuilder<int>.GetInstance(5 * classifiedSpans.Count, out var data); | |||
for (var currentClassifiedSpanIndex = 0; currentClassifiedSpanIndex < classifiedSpans.Count; currentClassifiedSpanIndex++) | |||
var data = s_tokenListPool.Allocate(); |
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 you use .GetPooledObject you can use a using
.
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.
signing off on the idea. but we do have a cleaner pattern here that doesn't need try/finally.
} | ||
finally | ||
{ | ||
data.Clear(); |
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.
i am fine not clearing an list of ints.
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.
Sure, went ahead and switched to GetPooledObject. Clearing will now occur upon retrieval from the pool.
This code was calling ArrayBuilder.ToArray, which would always allocate a new array as a result. Additionally, the arraybuilder itself would end up being large enough that it wouldn't end up going back into the pool. Thus, two large array were allocated on many calls into this method.
There really is no need for this method to use ArrayBuilder, as the code that ends up owning the resultant array doesn't attempt to put it back into a pool.
This shows up as about 0.5% of allocation in devenv in the customer profile I'm looking at, half of which should be removed by this change.