From 20c53142d1a491be30b602c91e91bfebe248da95 Mon Sep 17 00:00:00 2001 From: Todd Grunke Date: Thu, 13 Feb 2025 15:39:21 -0800 Subject: [PATCH] WIP: Switch TextDocumentState.GetTextVersionAsync to ValueTask to reduce allocations. The task creation from calling this method accounts for 34 MB (0.2%) of allocations in the CSharpEditingTests.Completion speedometer test. Going to run a test insertion to verify that this gets rid of the majority of these allocations before proceeding. --- .../Core/Portable/Workspace/Solution/ProjectState.cs | 8 ++++---- .../Core/Portable/Workspace/Solution/TextDocument.cs | 4 ++-- .../Core/Portable/Workspace/Solution/TextDocumentState.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs index 94bd2575abfd3..b764e8ab829ea 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs @@ -116,7 +116,7 @@ public ProjectState(LanguageServices languageServices, ProjectInfo projectInfo, DocumentStates = new TextDocumentStates(projectInfoFixed.Documents, info => CreateDocument(info, parseOptions, loadTextOptions)); AdditionalDocumentStates = new TextDocumentStates(projectInfoFixed.AdditionalDocuments, info => new AdditionalDocumentState(languageServices.SolutionServices, info, loadTextOptions)); - _lazyLatestDocumentVersion = AsyncLazy.Create(static (self, c) => ComputeLatestDocumentVersionAsync(self.DocumentStates, self.AdditionalDocumentStates, c), arg: this); + _lazyLatestDocumentVersion = AsyncLazy.Create(static async (self, c) => await ComputeLatestDocumentVersionAsync(self.DocumentStates, self.AdditionalDocumentStates, c).ConfigureAwait(false), arg: this); _lazyLatestDocumentTopLevelChangeVersion = AsyncLazy.Create(static (self, c) => ComputeLatestDocumentTopLevelChangeVersionAsync(self.DocumentStates, self.AdditionalDocumentStates, c), arg: this); // ownership of information on document has moved to project state. clear out documentInfo the state is @@ -220,7 +220,7 @@ private ProjectInfo FixProjectInfo(ProjectInfo projectInfo) return projectInfo; } - private static async Task ComputeLatestDocumentVersionAsync(TextDocumentStates documentStates, TextDocumentStates additionalDocumentStates, CancellationToken cancellationToken) + private static async ValueTask ComputeLatestDocumentVersionAsync(TextDocumentStates documentStates, TextDocumentStates additionalDocumentStates, CancellationToken cancellationToken) { // this may produce a version that is out of sync with the actual Document versions. var latestVersion = VersionStamp.Default; @@ -1090,8 +1090,8 @@ private void GetLatestDependentVersions( if (recalculateDocumentVersion) { - dependentDocumentVersion = AsyncLazy.Create(static (arg, cancellationToken) => - ComputeLatestDocumentVersionAsync(arg.newDocumentStates, arg.newAdditionalDocumentStates, cancellationToken), + dependentDocumentVersion = AsyncLazy.Create(static async (arg, cancellationToken) => + await ComputeLatestDocumentVersionAsync(arg.newDocumentStates, arg.newAdditionalDocumentStates, cancellationToken).ConfigureAwait(false), arg: (newDocumentStates, newAdditionalDocumentStates)); } else if (contentChanged) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs index d746eb8576229..7b7d0946f6418 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs @@ -90,8 +90,8 @@ internal SourceText GetTextSynchronously(CancellationToken cancellationToken) /// /// Gets the version of the document's text. /// - public Task GetTextVersionAsync(CancellationToken cancellationToken = default) - => State.GetTextVersionAsync(cancellationToken); + public async Task GetTextVersionAsync(CancellationToken cancellationToken = default) + => await State.GetTextVersionAsync(cancellationToken).ConfigureAwait(false); /// /// Fetches the current version for the document synchronously. diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs index dc92003f45237..cfc5deda9b82a 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs @@ -123,7 +123,7 @@ public VersionStamp GetTextVersionSynchronously(CancellationToken cancellationTo return textAndVersion.Version; } - public async Task GetTextVersionAsync(CancellationToken cancellationToken) + public async ValueTask GetTextVersionAsync(CancellationToken cancellationToken) { // try fast path first if (TryGetTextVersion(out var version))