-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Ensure that MEF is initialized using an old style non-async package #1560
Conversation
Ensure that MEF is initialized using an old style non-async package. This causes the Scanning new and updated MEF components... dialog to appear. Without this the GitHub pane will be blamed for degrading startup performance.
Looks great @jcansdale. Fantastic work m8. No performance warning banner. Legit improvements IMHO. Tested both Visual Studio versions with the same result👍 ✌️ "Because we can, can, can... Yes we can, can, can, can..." |
@bchavez Thanks for testing it. I'm relieved to hear it's working! 👍 |
Pre-initializing MEF is only required by GitHubPane.
I'm surprised that this actually avoids the warning infobar. It seems like it would just shift it to a different package, but still from your VSIX. @BertanAygun does this make sense to you? |
/// </summary> | ||
protected override void Initialize() | ||
{ | ||
GetService(typeof(SComponentModel)); |
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.
Can we remove this line and fix the tool window to not synchronously block on this service? Your tool window initialization could display something else while asynchronously awaiting MEF's initialization, thus the user experience is that VS starts up much more quickly, even if github's tool window is visible.
The VS 15.6 async tool window feature is basically a temporary control displayed while the window initializes, so you could make that up in your VSIX yourself and thus support it downlevel on VS 2015.
// This package must auto-load before its tool window is activated on startup. | ||
// We're using the GitSccProvider UI context because this is triggered before | ||
// tool windows are activated and we already use it elsewhere (the containing | ||
// assembly would have been loaded anyway). |
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.
VS Shell will already ensure your package is loaded before the tool window is activated so you don't have to do it here.
This auto load ensures that your package is loaded for every startup session regardless of your tool window is open slowing down startup for all users instead of just those with the toolwindow visible.
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.
VS Shell will already ensure your package is loaded before the tool window is activated so you don't have to do it here.
If we allow that to happen, our package gets blamed for MEF initialization (which can take 10 seconds 😨).
This auto load ensures that your package is loaded for every startup session regardless of your tool window is open slowing down startup for all users instead of just those with the toolwindow visible.
We need to auto-load on this context anyway in order to install a custom UIContext
. That's why I wasn't too concerned about loading this assembly.
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.
As you pointed, the cost is still there just becomes part of SCC package which is unique in this case since it is the one that causes your auto load unlike other scenarios. At the end of the day startup is still impacted by 10 seconds which is the important part. I have to mention that SCC hiding cost of auto loads from the UI context it sets is a known issue that we will fix soon btw.
As for your auto load reason, would you be able to use a rule based UI context to activate your UI context instead of auto loading a package?
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 have to mention that SCC hiding cost of auto loads from the UI context it sets is a known issue that we will fix soon btw.
Thanks, this is good to know.
As for your auto load reason, would you be able to use a rule based UI context to activate your UI context instead of auto loading a package?
Our UI context is a subset of the GitSccProvider
context (which appears to activate if VS was using Git the last time it launched). Is there a way to implement a custom UI context that doesn't involve loading a package?
Am I correct in thinking that a rule based UI context is a composite of existing UI context (you can't use them to create a completely custom context)?
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.
What are the conditions that you set the UI context in? If it is GIT SCC context and presence of your package, you can just define a rule based UI contexts that is only based on GIT SCC context. Since the rule based UI context will only be added when your pkgdef is deployed it will only be active when GIT SCC is active and user has your extension installed.
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.
What are the conditions that you set the UI context in?
Here is pseudo code for what we need:
If in GitSccProvider
context &&
IGitExt.ActiveRepositories.Count > 0
We're pretty much always in the GitSccProvider
context, because it's active even when there is no loaded solution but the previously loaded solution was in a Git repo. 😕 We therefore check the IGitExt
service to find out if we're really in the context of an active repo.
We have made efforts to only load when absolutely necessary! 😄
using Microsoft.VisualStudio.Shell; | ||
using Microsoft.VisualStudio.ComponentModelHost; | ||
|
||
namespace GitHub.VisualStudio |
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 would not approve this change as this doesn't really solve any performance issues. In fact it seems to make things worse as it adds synchronous query of MEF to startup path for those users that have Git provider set as default source control provider.
As @AArnott stated this would not solve any performance issues and just move cost between packages but since both packages are from same extension. If you run Visual Studio with /log switch, the activity log should output inclusive cost of each package and tool window to help with diagnosis. |
I've just tried that with this build. It appears that by using I believe this is what we were inadvertently doing in the past and why we never triggered the startup performance warning until we moved to an The thing is, we do want to trigger the following dialog so users know what is going on: Is there any other way to ensure that this dialog gets displayed short of calling |
@jcansdale, I would really recommend avoiding initializing MEF synchronously. Andrew has already good recommendations to be able to do that and starting in 15.6 you can use async tool window to make some of those changes easier. Unfortunately initializing MEF synchronously in startup will make sure all users that have GitHub installed to have really bad startup experience. |
There's an implementation of what you suggested here:
If you could take a look/review, that would be very much appreciated!
Before writing the above PR, I assumed the hit from MEF was only from when it initializes its cache after install. I hadn't appreciated the few second delay the first time the |
Made obsolete by #1569. |
This workaround causes the
Scanning new and updated MEF components...
dialog to appear. Without this theGitHub
pane will be blamed for degrading startup performance.What this PR does
It provokes MEF to initialize itself using an old style non-async package. This will happen before any tool windows are activated in the
GitSccProvider
auto-load context.All the
InitializeMefPackage
package does is callGetService(typeof(SComponentModel))
when it initializes. Visual Studio knows how to handle synchronous initialization of MEF and pops up theScanning new and updated MEF components...
dialog.The
InitializeMefPackage
package will only cause theGitHub.VisualStudio
assembly to load, and uses an auto-load context we already use inGitContextPackage
. It shouldn't degrade performance beyond the initial MEF initialization hit immediately after install.How to test
GitHub
pane is visibleTools > Clear MEF Component Cache...
NOTE: Visual Studio shows this banner based on an average startup time. You might need to do this a few times to being the average startup time back down. 😢 It should then consistently not appear.
Notes
I tried more sophisticated approaches but they didn't work nearly as well (or at all). For example:
When MEF is refreshing on a background thread, no
Scanning new and updated MEF components...
dialog appears. There were other issues that I wasn't able to resolve.We could probably resolve this issue by converting the
GitHub
pane into an async initializing tool window. Unfortunately this is only supported on recent versions of Visual Studio 2017. We would need to support two code paths and deal with separate Visual Studio 2017 assemblies.Related
https://docs.microsoft.com/en-us/visualstudio/extensibility/how-to-diagnose-extension-performance
Fixes #1550