Improving the responsiveness of critical scenarios by updating auto load behavior for extensions
The Visual Studio team partners with extension authors to provide a productive development environment for users, who rely on a rich ecosystem of quality extensions. Today, we’re introducing an update to extension auto load based on feedback from our community of developers, who need to quickly start Visual Studio and load their solution while deferring other functionality to load in the background.
As part of ongoing performance efforts to guarantee a faster startup and solution load experience for all users, Visual Studio will change how auto loaded packages work during startup and solution load scenarios. Please see the upcoming changes for extension authors below and let us know if you have any questions. The team is actively answering any questions you might have regarding this on the ExtendVS channel on Gitter.
In Visual Studio 2015, we added support for asynchronous packages (AsyncPackage base class) and asynchronous auto load. Extensions have been opting into asynchronous load to reduce performance issues since then. However, there are still some extensions that are loading synchronously, and it is negatively impacting the performance of Visual Studio.
In light of that, changes are coming to start the process of turning off synchronous auto load support. This will improve the user experience and guarantees a consistent startup and solution load experience, providing a responsive IDE. As part of this, changes to auto load behavior in a future Visual Studio update will be as follows:
- Async packages that load on the background have smaller performance impact than synchronously loaded packages, but still the cost is non-zero due to IO contention with foreground thread when starting up Visual Studio or opening a solution. To optimize startup and solution scenarios specifically, the IDE will not auto load async packages during those scenarios even on background threads. Instead the IDE will push all auto load requests into a queue. Once startup or solution load is completed, the IDE will start loading queued packages asynchronously as it detects pauses in user activity. This could mean that a package is never automatically loaded in that session if it’s a short session, or that packages which were queued to be loaded during startup might not load before a user opens a solution.
Please note that this covers all auto load requests regardless of the source UI context. For example, synchronous auto load requests from any UI context (e.g. SolutionHasSingleProject) or rule-based UI contexts that were previously activated while a solution was being loaded will not be added to the queue. Other sources of package loads, such as project factory queries and service queries, will not be impacted by this change.
- All packages that utilize auto load rules will have to support background load and implement asynchronous initialization. The IDE will no longer synchronously auto load packages in any UI context, including rule-based UI contexts.
While asynchronous load support was added in Visual Studio 2015, we know many extensions also want to support Visual Studio 2013 in a single package. In order to make that possible, we have provided a sample that shows how to create a Visual Studio package that loads synchronously in Visual Studio 2013 but also supports asynchronous load in Visual Studio 2015 and above.
The Visual Studio team is committed to working with extension owners to help make these changes as soon as possible and with as little disruption as possible for end-users. So, the changes will be phased in over multiple updates:
Visual Studio 2017, version 15.7:
- The Visual Studio Marketplace is posting a reminder during submission of a non-compliant extension (i.e., an extension that auto-loads but is not an async-package that supports background load).
- The Visual Studio SDK includes a new analyzer that will issue a build reminder for non-compliant extensions.
Visual Studio 2017, version 15.8:
- Async packages that support background load will be loaded after Visual Studio startup and solution load are completed (this is update #1 mentioned above).
In a later update, Visual Studio will completely disable auto-loading of synchronous extensions (update #2 mentioned above). End users will see a notification in Visual Studio informing them about extensions that were impacted.
Impact on package implementations:
These changes may require changes to existing packages that utilize the ProvideAutoLoad attribute and inherit from the Package base class, including but not limited to:
- Synchronous packages (those inheriting from the Package base class) must be converted to support asynchronous loading and enable background load. We also encourage package owners to move initialization code to the thread pool as much as possible to ensure users continue to see a responsive IDE. We will be monitoring extensions and UI delays to track responsiveness issues caused by auto loaded packages. You can find more information on diagnosing package auto load performance in our guidance on Microsoft Docs.
In order to catch potential issues with async conversion, we encourage all package owners to install the latest SDK and Threading analyzers from NuGet in to their projects.
- If your package needs to utilize the main thread because it calls into UI thread bound Visual Studio APIs that take a long time to execute, please let us know as we are looking for opportunities in converting such services to implement async methods or be free threaded to avoid responsiveness issues when loading packages in background.
- Packages that used to load at the beginning of solution load and rely on solution events will need to change implementation as they will no longer receive such events. Instead the package can enumerate the contents of a solution when the extension is loaded. See code sample.
- Like above, packages that used to load at startup and relied on solution events will have to handle the case where it is loaded after solution load is completed. It is possible for solution load to occur during and closely after startup giving IDE no chance to load startup packages (altering the load behavior of packages from previous versions of Visual Studio).
- Packages that register command status handlers will need to ensure their default command states are valid. With these changes there will be a timeframe where the QueryStatus handlers are not registered. Generally, we encourage package owners to utilize rule-based UI contexts as much as possible to determine command states via metadata instead of code-based QueryStatus handlers, and will be looking for feedback in what additional terms can be added to rule-based UI contexts to move away from code-based handlers.
Testing async packages that auto load in the background:
Update#1 mentioned above will change the timing of when async packages auto-load in the background. To help you test your package with this behavior, Visual Studio 2017 versions 15.6 and 15.7 include the new auto load manager in the product behind a feature flag (in version 15.8 Preview 2 and later this will be enabled by default). With this feature flag enabled, Visual Studio will defer auto-loading of async, background loadable packages until startup and solution load complete and Visual Studio is idle for some time. Synchronous auto-loading packages will have no change in behavior.
To enable the new auto load behavior, you can run both the following commands in your Visual Studio installation directory:
vsregedit set <VSROOT> HKCU FeatureFlagsShellAutoLoadRestrictions Value dword 1
vsregedit set <VSROOT> HKLM AutoLoadPackages AllowSynchronousLoads dword 1
You can use the following command to change the idle time to a large value to aid in testing your extension. For instance, to set the idle time to 60 seconds:
vsregedit set <VSROOT> HKLM AutoLoadPackages MinimumInputIdleTime dword 60000
To go back to existing behavior, you can run:
vsregedit set <VSROOT> HKCU FeatureFlagsShellAutoLoadRestrictions Value dword 0
- Creating an AsyncPackage: https://docs.microsoft.com/en-us/visualstudio/extensibility/how-to-use-asyncpackage-to-load-vspackages-in-the-background
- AsyncPackage on Solution Load sample: https://github.com/madskristensen/SolutionLoadSample
- VisibilityConstraints sample: https://github.com/madskristensen/VisibilityConstraintsSample
- Backwards compatible async package sample (Visual Studio 2013 through Visual Studio 2017): https://github.com/Microsoft/VSSDK-Extensibility-Samples/tree/master/Backwards_Compatible_AsyncPackage_2013
- Rule based UI contexts: https://docs.microsoft.com/en-us/visualstudio/extensibility/how-to-use-rule-based-ui-context-for-visual-studio-extensions
- Extension performance guidance: https://docs.microsoft.com/en-us/visualstudio/extensibility/how-to-diagnose-extension-performance
- Visual Studio threading analyzers: https://www.nuget.org/packages/Microsoft.VisualStudio.Threading.Analyzers/
- Visual Studio SDK analyzers: https://www.nuget.org/packages/Microsoft.VisualStudio.SDK.Analyzers