Skip to content
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

[LSP] Report unchanged results if diagnostic data is the same as last report #75587

Merged
merged 10 commits into from
Oct 23, 2024

Conversation

dibarbet
Copy link
Member

Resolves #75240

This updates the behavior of the version cache to also store and check against the hash of the last reported data. This allows us to report unchanged results when the data we re-calculate ends up being exactly the same.

This saves some overhead in serialization / deserialization and processing on the client side.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Analyzers untriaged Issues and PRs which have not yet been triaged by a lead labels Oct 22, 2024
{
await ComputeAndReportCurrentDiagnosticsAsync(
context, diagnosticSource, progress, newResultId, clientCapabilities, cancellationToken).ConfigureAwait(false);
ReportCurrentDiagnostics(
Copy link
Member Author

@dibarbet dibarbet Oct 22, 2024

Choose a reason for hiding this comment

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

Computation moved to run inside the cache based on what parameters it determines. Makes it much easier to reason about concurrency

/// </summary>
internal class DiagnosticsPullCache(string uniqueKey) : VersionedPullCache<(int globalStateVersion, VersionStamp? dependentVersion), (int globalStateVersion, Checksum dependentChecksum), DiagnosticsRequestState, DiagnosticData>(uniqueKey)
{
public override async Task<(int globalStateVersion, VersionStamp? dependentVersion)> ComputeCheapVersionAsync(DiagnosticsRequestState state, CancellationToken cancellationToken)
Copy link
Member Author

Choose a reason for hiding this comment

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

moved from passing functions to impls of abstract methods

{
/// <summary>
/// Internal cache item that updates state for a particular <see cref="Workspace"/> and <see cref="ProjectOrDocumentId"/> in <see cref="VersionedPullCache{TCheapVersion, TExpensiveVersion, TState, TComputedData}"/>
/// This type ensures that the state for a particular key is never updated concurrently for the same key (but different key states can be concurrent).
Copy link
Member Author

@dibarbet dibarbet Oct 22, 2024

Choose a reason for hiding this comment

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

prior to this change, there was a single semaphore around updating resultIds for the entire cache item. However now we need to also run the computation to determine if and how the cache should be updated. I did not want to block requests for other documents on computation of diagnostics for a different diagnostic. So now we have the CacheItem which gives a finer grained semaphore to an entry for a specific workspace+proj/doc.

@CyrusNajmabadi
Copy link
Member

LMK when you'd like a review :)

@dibarbet dibarbet marked this pull request as ready for review October 23, 2024 17:33
@dibarbet dibarbet requested a review from a team as a code owner October 23, 2024 17:33
CancellationToken cancellationToken)
{
// Ensure that we only update the cache item one at a time.
// This means that the computation of new data for this item only occurs sequentially.
Copy link
Member

Choose a reason for hiding this comment

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

aside: have we considered computing results in parallel higher up in workspace diagnostics? we walk the diagnostic sources serially. but we could use our parallel helpers to potentially speed that up.

Copy link
Member Author

Choose a reason for hiding this comment

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

Definitely potentially possible. I'll leave that to investigate in a different PR.

public async Task<(string, ImmutableArray<TComputedData>)?> UpdateCacheItemAsync(
VersionedPullCache<TCheapVersion, TExpensiveVersion, TState, TComputedData> cache,
PreviousPullResult? previousPullResult,
bool isFullyLoaded,
Copy link
Member

Choose a reason for hiding this comment

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

hrmm... what is isFullyLoaded...

Copy link
Member Author

@dibarbet dibarbet Oct 23, 2024

Choose a reason for hiding this comment

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

this is the operation progress stuff. We always recompute until we've fully loaded the sln. I'm not 100% convinced its necessary anymore (since checksums should change as we load), but I don't want to remove it in this PR.

writer.WriteInt32(position.Line);
writer.WriteInt32(position.Character);
}

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change

@dibarbet dibarbet merged commit 10f6afe into dotnet:main Oct 23, 2024
25 checks passed
@dibarbet dibarbet deleted the reuse_resultid branch October 23, 2024 21:41
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Oct 23, 2024

WriteDiagnosticDataLocation(diagnosticData.DataLocation, writer);

foreach (var additionalLocation in diagnosticData.AdditionalLocations)
Copy link
Contributor

Choose a reason for hiding this comment

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

AdditionalLocations

Are there usually very many items in here? If so, do they usually have the same file path?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I didn't notice there were multiple file spans per location. Maybe these can't be easily grouped by file location.

{
writer.WriteInt32(position.Line);
writer.WriteInt32(position.Character);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: trailing empty line

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Analyzers untriaged Issues and PRs which have not yet been triaged by a lead VSCode
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[LSP] Return the same resultId if the diagnostic report is the same
4 participants