Skip to content

Inline Hints Perf#55259

Merged
akhera99 merged 3 commits intodotnet:main-vs-depsfrom
akhera99:perf_inline_hints
Aug 4, 2021
Merged

Inline Hints Perf#55259
akhera99 merged 3 commits intodotnet:main-vs-depsfrom
akhera99:perf_inline_hints

Conversation

@akhera99
Copy link
Copy Markdown
Member

@akhera99 akhera99 commented Jul 30, 2021

Fixes: AB#1361128

Reconfigured code surrounding the creation of inline hint tags. Now we make sure we are in a span that is going to have a hint added prior to calling for the creation of a hint.
Also, Measure is very expensive and I was calling it on the border object rather than the textblock, but it was only necessary for the textblock.

@akhera99 akhera99 self-assigned this Jul 30, 2021
@akhera99 akhera99 requested a review from a team as a code owner July 30, 2021 00:22
@akhera99 akhera99 requested a review from a team July 30, 2021 00:22
@ghost ghost added the Area-IDE label Jul 30, 2021

var selectedSpans = new List<ITagSpan<IntraTextAdornmentTag>>();
foreach (var tagSpan in _cache)
for (var i = 0; i < _cache.Count; i++)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (var i = 0; i < _cache.Count; i++)
foreach (var (mappingTagSpan, tagSpan) in _cache)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The index is required for assigning a value back.

if (spans.IntersectsWith(tagSpan))
{
selectedSpans.Add(tagSpan);
if (_cache[i].tagSpan is not { } hintTagSpan)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (_cache[i].tagSpan is not { } hintTagSpan)
if (_cache[i].tagSpan is null)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changing to deconstructed foreach will change this slightly, but there's name collisions so it will depend on what you name the deconstructed parts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't work for lazy initialization.

}

var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();
var classify = document?.Project.Solution.Workspace.Options.GetOption(InlineHintsOptions.ColorHints, document?.Project.Language) ?? false;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var classify = document?.Project.Solution.Workspace.Options.GetOption(InlineHintsOptions.ColorHints, document?.Project.Language) ?? false;
var classify = document is null
? false
: document.Project.Solution.Workspace.Options.GetOption(InlineHintsOptions.ColorHints, document.Project.Language);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to keep the original form here so it's clear this is the same code just moved down.

}

// Encapsulates the textblock within a border. Gets foreground/background colors from the options menu.
block.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it's good to measure only what's needed, I imagine this won't be much of a perf gain. TextBlock measurement is the expensive part, the border likely had very little overhead here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this was an opportunistic improvement from the performance trace. The lazy evaluation is the big win, and this is the distant second but easy to fix.

/// stores the parameter hint tags in a global location
/// </summary>
private readonly List<ITagSpan<IntraTextAdornmentTag>> _cache;
private readonly List<(IMappingTagSpan<InlineHintDataTag> mappingTagSpan, ITagSpan<IntraTextAdornmentTag>? tagSpan)> _cache;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private readonly List<(IMappingTagSpan<InlineHintDataTag> mappingTagSpan, ITagSpan<IntraTextAdornmentTag>? tagSpan)> _cache;
private readonly List<(IMappingTagSpan<InlineHintDataTag> mappingTagSpan, ITagSpan<IntraTextAdornmentTag>? tagSpan)> _cache = new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lets you remove the line in the constructor and keeps it easy to change in the future if needed

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a better pattern to have, changed.

Copy link
Copy Markdown
Contributor

@ryzngard ryzngard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still not 100% sure what cases we're hitting the cache here. snapshot != _cacheSnapshot will be true for scrolling as well as typing right? or is that snapshot only for text changes and not the view changing?

tag.Tag.Hint, Format, _textView, dataTagSpan, _taggerProvider, _formatMap, classify);

_cache.Add(new TagSpan<IntraTextAdornmentTag>(dataTagSpan, parameterHintUITag));
_cache.Add((tag, null));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 named tuple element for null would be good

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

@sharwell
Copy link
Copy Markdown
Contributor

@ryzngard cache hits during scrolling. Lazy calculation of tags in the current view (previously was whole document) happens during typing.

@ryzngard
Copy link
Copy Markdown
Contributor

Ah, so the snapshot is the full document text and not the same as the ITextView.Snapshot property.

@sharwell
Copy link
Copy Markdown
Contributor

💭 They should be the same

@akhera99 akhera99 merged commit 5c151ec into dotnet:main-vs-deps Aug 4, 2021
@ghost ghost added this to the Next milestone Aug 4, 2021
@dibarbet dibarbet modified the milestones: Next, 17.0.P4 Aug 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants