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

Rework ProjectSnapshotManagerDispatcher to avoid creating a dedicated thread #9984

Merged
merged 47 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
246db4a
Assert the dispatcher thread in DefaultProjectSnapshotManager
DustinCampbell Feb 23, 2024
b1cc8e4
CSharpVirtualDocumentFactoryTest: Use real dispatcher
DustinCampbell Feb 23, 2024
b79a2ae
Clean up CSharpVirtualDocumentFactoryTest
DustinCampbell Feb 23, 2024
e9cf196
WorkspaceSemanticTokensRefreshTriggerTest: Use real dispatcher
DustinCampbell Feb 23, 2024
bd43542
Clean up WorkspaceSemanticTokensRefreshTriggerTest
DustinCampbell Feb 23, 2024
776fb79
Benchmarks: Use real dispatcher
DustinCampbell Feb 23, 2024
6e04ffb
Remove TestProjectSnapshotManagerDispatcher
DustinCampbell Feb 23, 2024
cbccdcb
RazorProjectInfoPublisherTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
a2d1fa4
Clean up RazorProjectInfoPublisherTest
DustinCampbell Feb 23, 2024
d8e2d94
BackgroundDocumentGeneratorTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
806ce2b
Unskip test
DustinCampbell Feb 23, 2024
38a4cb0
Clean up BackgroundDocumentGeneratorTest
DustinCampbell Feb 23, 2024
6000ada
DefaultProjectSnapshotManagerTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
8e9bd62
Clean up DefaultProjectSnapshotManagerTest
DustinCampbell Feb 23, 2024
89b9d02
OutOfProcTagHelperResolverTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
881404e
Clean up OutOfProcTagHelperResolverTest
DustinCampbell Feb 23, 2024
ba1b78f
VisualStudioFileChangeTrackerTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
4ad44e3
Clean up VisualStudioFileChangeTrackerTest
DustinCampbell Feb 23, 2024
41ad40c
FallbackProjectManagerTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
9efea52
Clean up FallbackProjectManagerTest
DustinCampbell Feb 23, 2024
d4f3fc4
RazorDynamicFileInfoProviderTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
64f850e
Clean up RazorDynamicFileInfoProviderTest
DustinCampbell Feb 23, 2024
5f45f41
ProjectWorkspaceStateGeneratorTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
57c315c
Clean up ProjectWorkspaceStateGeneratorTest
DustinCampbell Feb 23, 2024
d268749
ProjectSnapshotManagerProxyTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
13fefbe
Clean up ProjectSnapshotManagerProxyTest
DustinCampbell Feb 23, 2024
4520cd1
ImportDocumentManagerIntegrationTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
4763864
ImportDocumentManagerTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
23c4e5a
RazorDocumentManagerTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
583ae4a
Clean up RazorDocumentManagerTest
DustinCampbell Feb 23, 2024
c09eace
VisualStudioDocumentTrackerTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
db0560f
GeneratedDocumentPublisherTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
ddea43c
Clean up GeneratedDocumentPublisherTest
DustinCampbell Feb 23, 2024
8d4b9f3
RazorProjectServiceTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
1c3d0c3
Clean up RazorProjectServiceTest
DustinCampbell Feb 23, 2024
76be965
RazorDiagnosticsPublisherTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
a4f828e
DocumentContextFactoryTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
2e8ea76
Clean up DocumentContextFactoryTest
DustinCampbell Feb 23, 2024
a760a34
SnapshotResolverTest: Update to use dispatcher
DustinCampbell Feb 23, 2024
501ffae
Clean up SnapshotResolverTest
DustinCampbell Feb 24, 2024
c7fe0d9
Unify ProjectSnapshotManagerDispatcher implementations on IErrorReporter
DustinCampbell Feb 24, 2024
8fc1d8e
Fix break in ProjectMutationBenchmark
DustinCampbell Feb 24, 2024
f4ce9af
Merge ProjectSnapshotManagerDispatcher and ProjectSnapshotManagerDisp…
DustinCampbell Feb 24, 2024
97852da
WorkspaceProjectStateChangeDetectorTest: Remove odd static dispatcher
DustinCampbell Feb 24, 2024
39976f5
Clean up WorkspaceProjectStateChangeDetectorTest a bit
DustinCampbell Feb 24, 2024
80ea498
Use ThreadPool rather than dedicated dispatcher thread
DustinCampbell Feb 24, 2024
06734a5
Rename dispatcher's RunOnDispatcherAsync methods to RunAsync
DustinCampbell Feb 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public async Task InitializeRazorCSharpFormattingAsync()
var targetPath = "/Components/Pages/Generated.razor";

DocumentUri = new Uri(_filePath);
DocumentSnapshot = GetDocumentSnapshot(projectFilePath, _filePath, targetPath);
DocumentSnapshot = await GetDocumentSnapshotAsync(projectFilePath, _filePath, targetPath);
DocumentText = await DocumentSnapshot.GetTextAsync();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public async Task SetupAsync()
var targetPath = "/Components/Pages/Generated.razor";

DocumentUri = new Uri(_filePath);
DocumentSnapshot = GetDocumentSnapshot(projectFilePath, _filePath, targetPath);
DocumentSnapshot = await GetDocumentSnapshotAsync(projectFilePath, _filePath, targetPath);
DocumentText = await DocumentSnapshot.GetTextAsync();

RazorCodeActionRange = ToRange(razorCodeActionIndex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public async Task SetupAsync()
var targetPath = "/Components/Pages/Generated.razor";

DocumentUri = new Uri(_filePath);
DocumentSnapshot = GetDocumentSnapshot(projectFilePath, _filePath, targetPath);
DocumentSnapshot = await GetDocumentSnapshotAsync(projectFilePath, _filePath, targetPath);
DocumentText = await DocumentSnapshot.GetTextAsync();

RazorPosition = ToPosition(razorCodeActionIndex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public async Task InitializeRazorCSharpFormattingAsync()

var targetPath = "/Components/Pages/Generated.razor";

DocumentSnapshot = GetDocumentSnapshot(projectFilePath, _filePath, targetPath);
DocumentSnapshot = await GetDocumentSnapshotAsync(projectFilePath, _filePath, targetPath);

var codeDocument = await DocumentSnapshot.GetGeneratedOutputAsync();
CSharpDocument = codeDocument.GetCSharpDocument();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

#nullable disable
Expand Down Expand Up @@ -52,7 +52,7 @@ private protected virtual LanguageServerFeatureOptions BuildFeatureOptions()

private protected NoopLogger Logger { get; }

internal IDocumentSnapshot GetDocumentSnapshot(string projectFilePath, string filePath, string targetPath)
internal async Task<IDocumentSnapshot> GetDocumentSnapshotAsync(string projectFilePath, string filePath, string targetPath)
{
var intermediateOutputPath = Path.Combine(Path.GetDirectoryName(projectFilePath), "obj");
var hostProject = new HostProject(projectFilePath, intermediateOutputPath, RazorConfiguration.Default, rootNamespace: null);
Expand All @@ -61,16 +61,22 @@ internal IDocumentSnapshot GetDocumentSnapshot(string projectFilePath, string fi
var textLoader = TextLoader.From(TextAndVersion.Create(text, VersionStamp.Create()));
var hostDocument = new HostDocument(filePath, targetPath, FileKinds.Component);

var projectSnapshotManager = CreateProjectSnapshotManager();
projectSnapshotManager.ProjectAdded(hostProject);
var tagHelpers = CommonResources.LegacyTagHelpers;
var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers, CodeAnalysis.CSharp.LanguageVersion.CSharp11);
projectSnapshotManager.ProjectWorkspaceStateChanged(hostProject.Key, projectWorkspaceState);
projectSnapshotManager.DocumentAdded(hostProject.Key, hostDocument, textLoader);
var projectSnapshot = projectSnapshotManager.GetLoadedProject(hostProject.Key);
var projectManager = CreateProjectSnapshotManager();

var documentSnapshot = projectSnapshot.GetDocument(filePath);
return documentSnapshot;
await Dispatcher.RunAsync(
() =>
{
projectManager.ProjectAdded(hostProject);
var tagHelpers = CommonResources.LegacyTagHelpers;
var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers, CodeAnalysis.CSharp.LanguageVersion.CSharp11);
projectManager.ProjectWorkspaceStateChanged(hostProject.Key, projectWorkspaceState);
projectManager.DocumentAdded(hostProject.Key, hostDocument, textLoader);
},
CancellationToken.None);

var projectSnapshot = projectManager.GetLoadedProject(hostProject.Key);

return projectSnapshot.GetDocument(filePath);
}

private class NoopClientNotifierService : IClientConnection, IOnInitialized
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public async Task InitializeRazorSemanticAsync()
TargetPath = $"/Components/Pages/{fileName}.razor";

var documentUri = new Uri(filePath);
var documentSnapshot = GetDocumentSnapshot(ProjectFilePath, filePath, TargetPath);
var documentSnapshot = await GetDocumentSnapshotAsync(ProjectFilePath, filePath, TargetPath);
var version = 1;
DocumentContext = new VersionedDocumentContext(documentUri, documentSnapshot, projectContext: null, version);

Expand Down Expand Up @@ -100,7 +100,7 @@ await RazorSemanticTokenService.GetSemanticTokensAsync(

private async Task UpdateDocumentAsync(int newVersion, IDocumentSnapshot documentSnapshot, CancellationToken cancellationToken)
{
await ProjectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
await ProjectSnapshotManagerDispatcher.RunAsync(
() => VersionCache.TrackDocumentVersion(documentSnapshot, newVersion), cancellationToken).ConfigureAwait(false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public async Task InitializeRazorSemanticAsync()
TargetPath = "/Components/Pages/SemanticTokens.razor";

var documentUri = new Uri(filePath);
var documentSnapshot = GetDocumentSnapshot(ProjectFilePath, filePath, TargetPath);
var documentSnapshot = await GetDocumentSnapshotAsync(ProjectFilePath, filePath, TargetPath);
var version = 1;
DocumentContext = new VersionedDocumentContext(documentUri, documentSnapshot, projectContext: null, version);

Expand Down Expand Up @@ -125,7 +125,7 @@ public async Task RazorSemanticTokensRangeEndpointRangesAsync()
private async Task UpdateDocumentAsync(int newVersion, IDocumentSnapshot documentSnapshot,
CancellationToken cancellationToken)
{
await ProjectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
await ProjectSnapshotManagerDispatcher.RunAsync(
() => VersionCache.TrackDocumentVersion(documentSnapshot, newVersion), cancellationToken)
.ConfigureAwait(false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public async Task InitializeRazorSemanticAsync()
TargetPath = "/Components/Pages/FormattingTest.razor";

var documentUri = new Uri(filePath);
var documentSnapshot = GetDocumentSnapshot(ProjectFilePath, filePath, TargetPath);
var documentSnapshot = await GetDocumentSnapshotAsync(ProjectFilePath, filePath, TargetPath);
DocumentContext = new VersionedDocumentContext(documentUri, documentSnapshot, projectContext: null, version: 1);

var text = await DocumentSnapshot.GetTextAsync().ConfigureAwait(false);
Expand Down Expand Up @@ -112,7 +112,7 @@ public async Task RazorSemanticTokensRangeScrollingAsync()

private async Task UpdateDocumentAsync(int newVersion, IDocumentSnapshot documentSnapshot)
{
await ProjectSnapshotManagerDispatcher!.RunOnDispatcherThreadAsync(
await ProjectSnapshotManagerDispatcher!.RunAsync(
() => VersionCache!.TrackDocumentVersion(documentSnapshot, newVersion), CancellationToken.None).ConfigureAwait(false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#nullable disable

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
Expand All @@ -13,40 +14,49 @@ namespace Microsoft.AspNetCore.Razor.Microbenchmarks;
public class BackgroundCodeGenerationBenchmark : ProjectSnapshotManagerBenchmarkBase
{
[IterationSetup]
public void Setup()
public async Task SetupAsync()
{
SnapshotManager = CreateProjectSnapshotManager();
SnapshotManager.ProjectAdded(HostProject);
SnapshotManager.Changed += SnapshotManager_Changed;
ProjectManager = CreateProjectSnapshotManager();

await Dispatcher.RunAsync(
() => ProjectManager.ProjectAdded(HostProject),
CancellationToken.None);

ProjectManager.Changed += SnapshotManager_Changed;
}

[IterationCleanup]
public void Cleanup()
{
SnapshotManager.Changed -= SnapshotManager_Changed;
ProjectManager.Changed -= SnapshotManager_Changed;

Tasks.Clear();
}

private List<Task> Tasks { get; } = new List<Task>();

private DefaultProjectSnapshotManager SnapshotManager { get; set; }
private DefaultProjectSnapshotManager ProjectManager { get; set; }

[Benchmark(Description = "Generates the code for 100 files", OperationsPerInvoke = 100)]
public async Task BackgroundCodeGeneration_Generate100FilesAsync()
{
for (var i = 0; i < Documents.Length; i++)
{
SnapshotManager.DocumentAdded(HostProject.Key, Documents[i], TextLoaders[i % 4]);
}
await Dispatcher.RunAsync(
() =>
{
for (var i = 0; i < Documents.Length; i++)
{
ProjectManager.DocumentAdded(HostProject.Key, Documents[i], TextLoaders[i % 4]);
}
},
CancellationToken.None);

await Task.WhenAll(Tasks);
}

private void SnapshotManager_Changed(object sender, ProjectChangeEventArgs e)
{
// The real work happens here.
var project = SnapshotManager.GetLoadedProject(e.ProjectKey);
var project = ProjectManager.GetLoadedProject(e.ProjectKey);
var document = project.GetDocument(e.DocumentFilePath);

Tasks.Add(document.GetGeneratedOutputAsync());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#nullable disable

using System.Threading;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;

Expand All @@ -13,19 +15,24 @@ public class ProjectLoadBenchmark : ProjectSnapshotManagerBenchmarkBase
[IterationSetup]
public void Setup()
{
SnapshotManager = CreateProjectSnapshotManager();
ProjectManager = CreateProjectSnapshotManager();
}

private DefaultProjectSnapshotManager SnapshotManager { get; set; }
private DefaultProjectSnapshotManager ProjectManager { get; set; }

[Benchmark(Description = "Initializes a project and 100 files", OperationsPerInvoke = 100)]
public void ProjectLoad_AddProjectAnd100Files()
public async Task ProjectLoad_AddProjectAnd100Files()
{
SnapshotManager.ProjectAdded(HostProject);
await Dispatcher.RunAsync(
() =>
{
ProjectManager.ProjectAdded(HostProject);

for (var i = 0; i < Documents.Length; i++)
{
SnapshotManager.DocumentAdded(HostProject.Key, Documents[i], TextLoaders[i % 4]);
}
for (var i = 0; i < Documents.Length; i++)
{
ProjectManager.DocumentAdded(HostProject.Key, Documents[i], TextLoaders[i % 4]);
}
},
CancellationToken.None);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,18 @@

#nullable disable

using System;
using System.Threading;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;

namespace Microsoft.AspNetCore.Razor.Microbenchmarks;

public class ProjectMutationBenchmark : ProjectSnapshotManagerBenchmarkBase
{
private readonly ProjectSnapshotManagerDispatcher _dispatcher;

public ProjectMutationBenchmark()
: base(100000)
{
_dispatcher = new SnapshotDispatcher(nameof(ProjectMutationBenchmark));
}

private Thread _addRemoveThread;
Expand All @@ -29,17 +23,17 @@ public ProjectMutationBenchmark()
[IterationSetup]
public void Setup()
{
SnapshotManager = CreateProjectSnapshotManager();
ProjectManager = CreateProjectSnapshotManager();
}

private DefaultProjectSnapshotManager SnapshotManager { get; set; }
private DefaultProjectSnapshotManager ProjectManager { get; set; }

[Benchmark(Description = "Does thread contention add/remove of documents", OperationsPerInvoke = 100)]
public async Task ProjectMutation_Mutates100kFilesAsync()
{
await _dispatcher.RunOnDispatcherThreadAsync(() =>
await Dispatcher.RunAsync(() =>
{
SnapshotManager.ProjectAdded(HostProject);
ProjectManager.ProjectAdded(HostProject);
}, CancellationToken.None);

var cancellationSource = new CancellationTokenSource();
Expand All @@ -51,9 +45,9 @@ await _dispatcher.RunOnDispatcherThreadAsync(() =>
for (var i = 0; i < Documents.Length; i++)
{
var document = Documents[i];
await _dispatcher.RunOnDispatcherThreadAsync(() => SnapshotManager.DocumentAdded(HostProject.Key, document, TextLoaders[i % 4]), CancellationToken.None).ConfigureAwait(false);
await Dispatcher.RunAsync(() => ProjectManager.DocumentAdded(HostProject.Key, document, TextLoaders[i % 4]), CancellationToken.None).ConfigureAwait(false);
Thread.Sleep(0);
await _dispatcher.RunOnDispatcherThreadAsync(() => SnapshotManager.DocumentRemoved(HostProject.Key, document), CancellationToken.None).ConfigureAwait(false);
await Dispatcher.RunAsync(() => ProjectManager.DocumentRemoved(HostProject.Key, document), CancellationToken.None).ConfigureAwait(false);
Thread.Sleep(0);
}

Expand All @@ -70,9 +64,9 @@ await _dispatcher.RunOnDispatcherThreadAsync(() =>
return;
}

await _dispatcher.RunOnDispatcherThreadAsync(() => SnapshotManager.GetProjects(), CancellationToken.None).ConfigureAwait(false);
await Dispatcher.RunAsync(() => ProjectManager.GetProjects(), CancellationToken.None).ConfigureAwait(false);
Thread.Sleep(0);
await _dispatcher.RunOnDispatcherThreadAsync(() => SnapshotManager.GetOpenDocuments(), CancellationToken.None).ConfigureAwait(false);
await Dispatcher.RunAsync(() => ProjectManager.GetOpenDocuments(), CancellationToken.None).ConfigureAwait(false);
Thread.Sleep(0);
}
});
Expand All @@ -86,16 +80,4 @@ await _dispatcher.RunOnDispatcherThreadAsync(() =>
Thread.Sleep(0);
}
}

private class SnapshotDispatcher : ProjectSnapshotManagerDispatcherBase
{
public SnapshotDispatcher(string threadName) : base(threadName)
{
}

public override void LogException(Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
}
}

This file was deleted.

Loading