-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Reduce File I/O under the AnalyzerAssemblyLoader folder #72412
Reduce File I/O under the AnalyzerAssemblyLoader folder #72412
Conversation
…lyLoader folder. Assemblies and their corresponding resource dlls are copied/deleted under this folder on solution open. When opening Rosly, I see about 700 dlls copied/deleted under this folder. Over 90% of these dlls are resource dlls, not something in use for my setup. This change is very rough, but attempts to separate the code that ensures the assembly is shadow-copied properly, from the code that ensures that it's supporting resource assemblies are shadow-copied properly. With this change locally, I see over 90% reduction in the number of these file I/O operations.
@jaredpar -- passed tests locally without any changes to the tests, we'll see what the ci says. Probably needs some cleanup, and I'm open to different ways to achieve this if you have ideas. |
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs
Outdated
Show resolved
Hide resolved
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs
Outdated
Show resolved
Hide resolved
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs
Outdated
Show resolved
Hide resolved
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs
Outdated
Show resolved
Hide resolved
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Desktop.cs
Outdated
Show resolved
Hide resolved
Added some comments Made culture check similar to old check in net core assembly resolver
Elevating out of draft status |
How will this change work for developers with non-English locales? I think the mentality for this change should be to assume that for a given build most analyzers will produce at least one diagnostic. On a non-English machine wouldn't this cause the satellite assembly load to trigger on every build where as for English it doesn't trigger? If so should we consider something like copying the satellite assemblies for |
It might be best to chat in person for this as I'm not completely clear on the concerns. Both desktop/core AssemblyResolve paths call into GetSatelliteInfoForPath for resource assemblies. That method calls into GetSatelliteAssemblyInfoForPath which will only do the call to PrepareSatelliteAssembliesToLoad if the _analyzerSatelliteAssemblyInfoMap doesn't already contain that path. There is a potential optimization here where only the resource assembly for the requested culture is prepared when requested instead of all cultures being prepared. I didn't go that route for simplicity concerns. As pointed out earlier, once you get into a multithreaded situation with differing write values, things can get tricky. Let me know if this is something you would like me to look into as part of this PR, or if I've completely misunderstood your concerns. In reply to: 1984315411 |
Modified to individually copy over satellite assemblies as they are requested. Let me know whether this alleviates your concerns. |
|
||
var tcs = new TaskCompletionSource<bool>(); | ||
var task = _mvidSatelliteAssemblyPathMap.GetOrAdd((mvid, cultureName), tcs.Task); | ||
if (object.ReferenceEquals(task, tcs.Task)) |
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.
Non-blocking: The management of the Task
here is virtually the same between the two methods. Feels like a case where we should be able to write it once and use it in both places. Don't have a lot of great recommendations though on best way to do this.
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 had doubts, but the merging ended up being pretty clean after I changed the Task types to match
(satelliteAssemblyPath, var actualCultureName) = getSatelliteAssemblyLocation(originalAnalyzerPath, cultureInfo); | ||
if (actualCultureName != null) | ||
{ | ||
PrepareSatelliteAssemblyToLoad(originalAnalyzerPath, actualCultureName); |
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.
In this model it's possible that PrepareSatelliteAssemblyToLoad
is called twice with the same arguments. Consider if only the ES
culture assembly is present but we get calls to load es-es
then es
. Will the impl of this method be correct in the case it's called twice with same arguments?
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 think the current code is fine. This code mimics how the non-satellite assembly is prepared via the call to PreparePathToLoad, as that could also be called twice with the same arg. The walk up the CultureInfo chain happens on the original path, which shouldn't be affected by any simultaneous file io occurring via PrepareSatelliteAssemblyToLoad.
@jjonescz, @RikkiGibson PTAL |
How does separating shadow-copying the non-resource assembly from shadow-copying the resources assemblies reduce file I/O? I assume some copies are avoided, but I don't understand which ones. |
Previously, all resource assemblies were shadow copied (usually around 10 per assembly). Now, they are copied on-demand. If I run my machine in the default english locale, no resource assemblies are now copied. If an assembly resolve comes for a different locale for some reason, then that resource assembly is shadow copied over before returning it. |
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Desktop.cs
Outdated
Show resolved
Hide resolved
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs
Outdated
Show resolved
Hide resolved
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs
Outdated
Show resolved
Hide resolved
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs
Show resolved
Hide resolved
It looks like there are legitimate test failures for the latest revision |
OK, think I fixed. Unit test code path wasn't changing an extension to indicate a resource assembly. |
* upstream/main: (1045 commits) Fix excessive compilation times due to speculative parsing after an incomplete string (#72565) Convert official pipeline to 1ES template (#72430) Fix #69628 Analyzer summary should show suppressor ID (#72569) Fix event hookup even when in a projection buffer Drop win32-ia32 language server support Remove workaround for .net7 r2r assembly loading issue remove unused usings Share compilation when generators don't produce any generated files Fix potential exception in AssetProvider.SynchronizeAssetsAsync (#72597) Fix Update __arglist.md (#72523) Improve code gen for concatenation of `string` and `char` (#71793) Reduce File I/O under the AnalyzerAssemblyLoader folder (#72412) Reduce allocations in AbstractTypeMap (#72588) disable diagnostics when solution crawler option is disabled disable diagnostics when solution crawler option is disabled better thread transitions Fix Add check Fix ...
Assemblies and their corresponding resource dlls are copied/deleted under this folder on solution open. When opening Roslyn, I see about 700 dlls copied/deleted under this folder. Over 90% of these dlls are resource dlls, not something in use for my setup.
This change separates the code that ensures the assembly is shadow-copied properly, from the code that ensures the supporting resource assemblies are shadow-copied properly.
With this change there is a 90% reduction in the number of files shadow copied into the AnalyzerAssemblyLoader folder during roslyn solution load.
Did a test insertion with a speedometer run to make sure it did what I thought. Below images are from RichCopyTest.CopyPlain speedometer run, RoslynCodeAnalysisService process, FileIO/Create events for dlls filtered under AnalyzerAssemblyLoader folder
*** old (313 records):
*** new (106 records)
I also looked at the CompletionText.Completion speedometer data and it decreased from 227 records to 52.