-
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
Reduce LOH allocs when applying code fixes. #73424
Changes from 11 commits
e754fb9
f876667
9b3fe96
33b9685
f9ac16b
8569d9d
7ece11a
6365421
3219183
5c58359
138049f
f754a6c
ddad624
6a4e3a8
7c563f6
6244809
594cd94
6f8a46b
2e191c8
450e0a9
940ce0f
30674f4
d446cb8
531a9d5
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 |
---|---|---|
|
@@ -62,8 +62,8 @@ internal async Task<LinkedFileMergeSessionResult> MergeDiffsAsync(IMergeConflict | |
} | ||
|
||
private async Task<LinkedFileMergeResult> MergeLinkedDocumentGroupAsync( | ||
IEnumerable<DocumentId> allLinkedDocuments, | ||
IEnumerable<DocumentId> linkedDocumentGroup, | ||
ImmutableArray<DocumentId> allLinkedDocuments, | ||
IGrouping<string, DocumentId> linkedDocumentGroup, | ||
LinkedFileDiffMergingSessionInfo sessionInfo, | ||
IMergeConflictHandler mergeConflictHandler, | ||
CancellationToken cancellationToken) | ||
|
@@ -73,7 +73,8 @@ private async Task<LinkedFileMergeResult> MergeLinkedDocumentGroupAsync( | |
// Automatically merge non-conflicting diffs while collecting the conflicting diffs | ||
|
||
var textDifferencingService = oldSolution.Services.GetRequiredService<IDocumentTextDifferencingService>(); | ||
var appliedChanges = await textDifferencingService.GetTextChangesAsync(oldSolution.GetDocument(linkedDocumentGroup.First()), newSolution.GetDocument(linkedDocumentGroup.First()), cancellationToken).ConfigureAwait(false); | ||
var appliedChanges = await textDifferencingService.GetTextChangesAsync( | ||
oldSolution.GetDocument(linkedDocumentGroup.First()), newSolution.GetDocument(linkedDocumentGroup.First()), TextDifferenceTypes.Line, cancellationToken).ConfigureAwait(false); | ||
var unmergedChanges = new List<UnmergedDocumentChanges>(); | ||
|
||
foreach (var documentId in linkedDocumentGroup.Skip(1)) | ||
|
@@ -93,10 +94,10 @@ private async Task<LinkedFileMergeResult> MergeLinkedDocumentGroupAsync( | |
|
||
// Add comments in source explaining diffs that could not be merged | ||
|
||
IEnumerable<TextChange> allChanges; | ||
IList<TextSpan> mergeConflictResolutionSpan = []; | ||
ImmutableArray<TextChange> allChanges; | ||
var mergeConflictResolutionSpan = new List<TextSpan>(); | ||
|
||
if (unmergedChanges.Any()) | ||
if (unmergedChanges.Count != 0) | ||
{ | ||
mergeConflictHandler ??= oldSolution.GetDocument(linkedDocumentGroup.First()).GetLanguageService<ILinkedFileMergeConflictCommentAdditionService>(); | ||
var mergeConflictTextEdits = mergeConflictHandler.CreateEdits(originalSourceText, unmergedChanges); | ||
|
@@ -125,12 +126,13 @@ private static async Task<ImmutableArray<TextChange>> AddDocumentMergeChangesAsy | |
CancellationToken cancellationToken) | ||
{ | ||
var unmergedDocumentChanges = new List<TextChange>(); | ||
var successfullyMergedChanges = ArrayBuilder<TextChange>.GetInstance(); | ||
using var _ = ArrayBuilder<TextChange>.GetInstance(out var successfullyMergedChanges); | ||
|
||
var cumulativeChangeIndex = 0; | ||
|
||
var textchanges = await textDiffService.GetTextChangesAsync(oldDocument, newDocument, cancellationToken).ConfigureAwait(false); | ||
foreach (var change in textchanges) | ||
var textChanges = await textDiffService.GetTextChangesAsync( | ||
oldDocument, newDocument, TextDifferenceTypes.Line, cancellationToken).ConfigureAwait(false); | ||
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. switching to Line-based-diff is a major win here. We normally do word-based, which leads to massive allocations in hte VS side (they're the impl of this service). |
||
foreach (var change in textChanges) | ||
{ | ||
while (cumulativeChangeIndex < cumulativeChanges.Count && cumulativeChanges[cumulativeChangeIndex].Span.End < change.Span.Start) | ||
{ | ||
|
@@ -196,25 +198,25 @@ private static async Task<ImmutableArray<TextChange>> AddDocumentMergeChangesAsy | |
groupSessionInfo.IsolatedDiffs++; | ||
} | ||
|
||
if (unmergedDocumentChanges.Any()) | ||
if (unmergedDocumentChanges.Count != 0) | ||
{ | ||
unmergedChanges.Add(new UnmergedDocumentChanges( | ||
unmergedDocumentChanges.AsEnumerable(), | ||
unmergedDocumentChanges, | ||
oldDocument.Project.Name, | ||
oldDocument.Id)); | ||
} | ||
|
||
return successfullyMergedChanges.ToImmutableAndFree(); | ||
return successfullyMergedChanges.ToImmutable(); | ||
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.
CyrusNajmabadi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
private static IEnumerable<TextChange> MergeChangesWithMergeFailComments( | ||
IEnumerable<TextChange> mergedChanges, | ||
IEnumerable<TextChange> commentChanges, | ||
IList<TextSpan> mergeConflictResolutionSpans, | ||
private static ImmutableArray<TextChange> MergeChangesWithMergeFailComments( | ||
ImmutableArray<TextChange> mergedChanges, | ||
List<TextChange> commentChanges, | ||
List<TextSpan> mergeConflictResolutionSpans, | ||
LinkedFileGroupSessionInfo groupSessionInfo) | ||
{ | ||
var mergedChangesList = NormalizeChanges(mergedChanges).ToList(); | ||
var commentChangesList = NormalizeChanges(commentChanges).ToList(); | ||
var mergedChangesList = NormalizeChanges(mergedChanges); | ||
var commentChangesList = NormalizeChanges(commentChanges); | ||
|
||
var combinedChanges = new List<TextChange>(); | ||
var insertedMergeConflictCommentsAtAdjustedLocation = 0; | ||
|
@@ -270,17 +272,15 @@ private static IEnumerable<TextChange> MergeChangesWithMergeFailComments( | |
groupSessionInfo.InsertedMergeConflictComments = commentChanges.Count(); | ||
groupSessionInfo.InsertedMergeConflictCommentsAtAdjustedLocation = insertedMergeConflictCommentsAtAdjustedLocation; | ||
|
||
return NormalizeChanges(combinedChanges); | ||
return NormalizeChanges(combinedChanges).ToImmutableArray(); | ||
} | ||
|
||
private static IEnumerable<TextChange> NormalizeChanges(IEnumerable<TextChange> changes) | ||
private static IList<TextChange> NormalizeChanges(IList<TextChange> changes) | ||
{ | ||
if (changes.Count() <= 1) | ||
{ | ||
if (changes.Count <= 1) | ||
return changes; | ||
} | ||
|
||
changes = changes.OrderBy(c => c.Span.Start); | ||
var orderedChanges = changes.OrderBy(c => c.Span.Start).ToList(); | ||
var normalizedChanges = new List<TextChange>(); | ||
|
||
var currentChange = changes.First(); | ||
|
@@ -309,7 +309,7 @@ public void LogLinkedFileResult(LinkedFileGroupSessionInfo info) | |
=> LinkedFileGroups.Add(info); | ||
} | ||
|
||
internal class LinkedFileGroupSessionInfo | ||
internal sealed class LinkedFileGroupSessionInfo | ||
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. |
||
{ | ||
public int LinkedDocuments; | ||
public int DocumentsWithChanges; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,9 +9,9 @@ | |
|
||
namespace Microsoft.CodeAnalysis; | ||
|
||
internal sealed class UnmergedDocumentChanges(IEnumerable<TextChange> unmergedChanges, string projectName, DocumentId documentId) | ||
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. |
||
internal sealed class UnmergedDocumentChanges(List<TextChange> unmergedChanges, string projectName, DocumentId documentId) | ||
{ | ||
public IEnumerable<TextChange> UnmergedChanges { get; } = unmergedChanges; | ||
public List<TextChange> UnmergedChanges { get; } = unmergedChanges; | ||
public string ProjectName { get; } = projectName; | ||
public DocumentId DocumentId { get; } = documentId; | ||
} |
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.
changed a lot of the APIs to not be IEnumerable-bases (as it's impossible to tell what is lazy and waht isn't). this also means things like enumerations don't allocate.