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

Add TypeCacheEvaluator separate to TypeCache to allow customization of already loaded assemblies #1324

Closed
GreenKn1ght opened this issue May 16, 2019 · 23 comments

Comments

Projects
None yet
2 participants
@GreenKn1ght
Copy link
Contributor

commented May 16, 2019

TypeCache initialization takes about 2 out of 10 seconds of startup time. This time is significantly increased on weak devices.
Xamarin.Android eagerly loads all assemblies. This means that in our application TypeCache processing 114 assemblies at startup. This causing pretty large impact on performace. And we can't even ignore assemblies (or types) by TypeCache.ShouldIgnoreAssemblyEvaluators (or ShouldIgnoreTypeEvaluators) because initialization starts automatically by ModuleInitializer or by ServiceLocator.Default, though call of this property will execute static ctor anyway.

Platform: Xamarin.Android 9.1

@GeertvanHorrik

This comment has been minimized.

Copy link
Member

commented May 16, 2019

Good point, I had something similar with UWP apps. I did some additional work around the initialization there. 114 assemblies is a lot to process though, let me check if I can think of something that can work around this.

@GeertvanHorrik

This comment has been minimized.

Copy link
Member

commented May 16, 2019

What if we could create a new type called TypeCacheEvaluator. This won't load anything, and will be loaded in the static ctor of TypeCache, but will be able to be customized before the static ctor hits the existing assemblies.

@GeertvanHorrik GeertvanHorrik changed the title TypeCache initialization heavily affects Xamarin.Android startup time. Add TypeCacheEvaluator separate to TypeCache to allow customization of already loaded assemblies May 16, 2019

GeertvanHorrik added a commit that referenced this issue May 16, 2019

@GeertvanHorrik

This comment has been minimized.

Copy link
Member

commented May 16, 2019

Releasing Build - 5.11.0-alpha.54, you should be able to update TypeCacheEvaluator before the TypeCache kicks in.

@GreenKn1ght

This comment has been minimized.

Copy link
Contributor Author

commented May 16, 2019

I can not profile the application right now, so I'm trying to find out if it works by other signs.

@GreenKn1ght

This comment has been minimized.

Copy link
Contributor Author

commented May 16, 2019

By the way, something is messed up here: InitializeAssemblies adds ignored assemblies to _loadedAssemblies and does not log about it; OnAssemblyLoaded does not add ignored assemblies to _loadedAssemblies and logs about it.

@GreenKn1ght

This comment has been minimized.

Copy link
Contributor Author

commented May 16, 2019

I ignored all assemblies (TypeCacheEvaluator.AssemblyEvaluators.Add (assembly => true) at entry point).
TypeCache.GetTypes (allowInitialization: false) returns 23000 types. I'm there must be 0.

@GeertvanHorrik

This comment has been minimized.

Copy link
Member

commented May 16, 2019

Good points. I was also thinking, maybe we should have autoLoad and explicitLoad assemblies.

@GreenKn1ght

This comment has been minimized.

Copy link
Contributor Author

commented May 16, 2019

When and where ModuleInitializer is called? I know about Fody.ModuleInit, but how it actually works? Could it be that ModuleInitializer is called before my code runs?

@GeertvanHorrik

This comment has been minimized.

Copy link
Member

commented May 16, 2019

As soon as the assembly is loaded into the appdomain. But it doesn't necessarily load the assemblies just yet. Only whenever the TypeCache type is used, so you should be able to customize the TypeCacheEvaluator upfront. Maybe it's Catel.MVVM resolving it first?

@GreenKn1ght

This comment has been minimized.

Copy link
Contributor Author

commented May 16, 2019

As I mentioned, Xamarin.Android eagerly loads (i.e. preloads) assemblies. So yes, when my code runs, they are already loaded into AD.

@GreenKn1ght

This comment has been minimized.

Copy link
Contributor Author

commented May 16, 2019

Hm, I can try to put my code into ModuleInit, but not sure if I should rely on loading order or not =/

@GeertvanHorrik

This comment has been minimized.

Copy link
Member

commented May 16, 2019

There is no order reload, but again, technically the code shouldn't invoke TypeCache. I will try to debug this tomorrow.

@GeertvanHorrik

This comment has been minimized.

Copy link
Member

commented May 17, 2019

But even if they are loaded, the module init code of Catel should not invoke any TypeCache stuff if I am not mistaken. Now trying to investigate this.

@GreenKn1ght

This comment has been minimized.

Copy link
Contributor Author

commented May 17, 2019

I read the code again and here is a chain of method calls:
ModuleInitializer.Initialize() ->
ServiceLocator.Default ->
IoCConfiguration.DefaultServiceLocator ->
IoCConfiguration.UpdateDefaultComponents() ->
IoCFactory.CreateServiceLocator() ->
static IoCFactory() ctor ->
TypeCache.AssemblyLoaded += ->
static TypeCache ctor.

@GeertvanHorrik

This comment has been minimized.

Copy link
Member

commented May 17, 2019

I will move the default initialization call to the first typecache call (making it a bit easier to control).

GeertvanHorrik added a commit that referenced this issue May 17, 2019

@GeertvanHorrik

This comment has been minimized.

Copy link
Member

commented May 17, 2019

Please try Build - 5.11.0-alpha.58

@GreenKn1ght

This comment has been minimized.

Copy link
Contributor Author

commented May 17, 2019

At first glance it works well.
Profiling will take a while.

@GreenKn1ght

This comment has been minimized.

Copy link
Contributor Author

commented May 17, 2019

By the way, which assemblies I shouldn't ignore so that Catel works most efficiently?

@GeertvanHorrik

This comment has been minimized.

Copy link
Member

commented May 17, 2019

If you don't need the serialization engine for system types, you could ignore anything that starts with "System." and see if that boosts performance.

@GreenKn1ght

This comment has been minimized.

Copy link
Contributor Author

commented May 17, 2019

Even if I don't ignore anything, TypeCache.InitializedAssemblies contains only 17 assemblies. Looks like great optimization! All of them starts with "System." except Mono.Security. Can't say why Mono.Security got into TypeCache. I think I'll ignore them all.

var assemblies = TypeCache.GetTypes(allowInitialization: false).Select(x => x.Assembly.FullName).Distinct();
var except = assemblies.Except(TypeCache.InitializedAssemblies).ToList();

It is interesting that except isn't empty: it contains assembly of app (view and view models are here).

@GeertvanHorrik

This comment has been minimized.

Copy link
Member

commented May 17, 2019

Yes, we sometimes do forced initialization of required assemblies (e.g. we definitely need the app assembly). Glad it's working much better for you, thanks for reporting. Let me know if this needs further work, or feel free to close it if it's solved to your satisfaction.

@GreenKn1ght

This comment has been minimized.

Copy link
Contributor Author

commented May 17, 2019

Thanks for the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.