-
Notifications
You must be signed in to change notification settings - Fork 199
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
Improve solution load performance #11591
Improve solution load performance #11591
Conversation
The IFileChangeDetector and IRazorFileChangeListener abstractions are no longer needed. This change removes them and merges the functionality into a single WorkspaceRootPathWatcher (replacing FileChangeDetectorManager).
When the WorkspaceRootPathWatcher starts it (currently) adds all *.razor and *.cshtml files under the root path to the RazorProjectService. It does this one file path at a time, which is pretty inefficient in large solutions, requiring lots of thread hopping for updates to the ProjectSnapshotManager. This change adds a bulk method that can be called to add an array of file paths in one update.
When RazorProjectEngine.OpenDocumentAsync is called, if the document needs to be added to the misc files project, it is added with a text loader that loads from disk. However, OpenDocumentAsync already has a SourceText in hand.
RazorProjectEngine calls into the TryResolveDocumentInAnyProject extension method, but that unnecessarily realizes a DocumentSnapshot. This change introduces TryFindContainingProject, which returns the first project that contains a document file path, rather than the DocumentSnapshot itself.
The language server always starts up by loading the misc files project with every *.razor or *.cshtml file in the workspace root path. This *might* be helpful for VS Code (though I'm unsure about that), but in VS, it's clearly unnecessary overhead. The RazorProjectService will regularly receive new project information from the IRazorProjectInfoDriver, so this is really unnecessary overhead.
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.
I'd be fine with the removal of the feature flag, and just never adding every file to the project manager, but I understand if you prefer to be cautious.
I think the string check is wrong though.
src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs
Outdated
Show resolved
Hide resolved
src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WorkspaceRootPathWatcher.cs
Outdated
Show resolved
Hide resolved
...icrosoft.AspNetCore.Razor.LanguageServer/Hosting/ConfigurableLanguageServerFeatureOptions.cs
Outdated
Show resolved
Hide resolved
To expand on my above comment a bit: in VS Code we sent |
I think we absolutely should do this. From my understanding have them in the misc project provides some functionality but not anything needed if it's not open (I'm still reading the PR). Definitely can be a separate PR but this would also help alleviate some of the delay in startup that @dibarbet has been looking at for vs code. |
I'd be delighted for somebody else to set the flag to test this out in VS Code. 😄
Why would we load every file from disk to send a |
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.
Love it. Been on my backlog for a bit and glad you got to it first :)
...icrosoft.AspNetCore.Razor.LanguageServer/Hosting/ConfigurableLanguageServerFeatureOptions.cs
Outdated
Show resolved
Hide resolved
src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs
Show resolved
Hide resolved
src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WorkspaceRootPathWatcher.cs
Outdated
Show resolved
Hide resolved
This is no longer true as of dotnet/vscode-csharp#7826 |
Needs must. It was the only way to get rzls to start generating code, to send to Roslyn, so that references to Razor components were valid. I guess I'm forgetting how we ended up getting that to happen. @ryzngard can you remind me? Is it just a side-effect of the named pipe, and our normal background document generator kicks in? |
If we're doing it at all it would be because of the background document generator. Let's get an issue filed on VS Code to make sure we include this fix there. I don't think we do the add anymore... if anything it would go through the dynamic file updates. That would also make this change safe on VS Code but it's worth testing |
src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs
Outdated
Show resolved
Hide resolved
This fixes a bug introduced in a prior commit to properly verify file extensions when a file is renamed. To do this, I've added a couple of polyfill-style methods to a new PathUtilities class located in Microsoft.AspNetCore.Utilities.Shared. These are the same as Path.GetExtension and Path.HasExtension but they provide span-based overloads for non-.NET Core scenarios.
The logic was doing the exact opposite of what the comments stated. We should *not* add a file path to the misc files project if it is already contained in a project. Instead, files were added if they were included in a project.
Currently, we're only disabling the behavior that fills the misc files project at language server initialization in VS-only. This commit makes the option more convenient to configure from the command-line to enable easier testing in VS Code. dotnet#11594 tracks that testing work and removing the behavior (and this option) completely.
Razor's language server does a lot of extra work to initialize that is really no longer necessary, at least in Visual Studio. This pull request is an attempt to remove a bunch of that extra work.
*.razor
and*.cshtml
files in the workspace root path. With theIRazorProjectInfoDriver
in place, I believe this to be unnecessary work. Note that I've left this behavior for VS Code for now, but we might remove it later.IRazorProjectServer
to add all of the documents to theProjectSnapshotManager
at once. Adding them one at a time results in a ton of extra asynchrony that slows solution load down as each document add hops around the thread pool.IRazorProjectService.OpenDocumentAsync(...)
is called, it first attempts to add the open document to the misc files project. This is because we might learn of an open document before the project system is done loading. However, it first adds the document using aTextLoader
that loads the file off disk. Then, it updates the document with theSourceText
that was passed toOpenDocumentAsync
. However, this causes the file to be loaded so that its contents can be compared with the newSourceText
. To avoid this additional I/O,OpenDocumentAsync
will now add the document to the misc files project with theSourceText
rather than aTextLoader
.DocumentSnapshot
instances unnecessarily when checking to see if a project contains a document file path.In addition, I've refactored all of the
IFileChangeDetector
andIRazorFileChangeListener
abstractions into the singleton,WorkspaceRootPathWatcher
. There was only a single implementation of each, so they really don't have a lot of value. I've similar unified a bunch of relevant tests.CI Build: https://dev.azure.com/dnceng/internal/_build/results?buildId=2656343&view=results
VS Test Insertion: https://dev.azure.com/devdiv/DevDiv/_git/VS/pullrequest/616458