Prism Module InitializationMode Comparison

Introduction

As part of my self-improvement challenge, I have been watching the Introduction to Prism course from Pluralsight. I chose this course so I am better equipped for my team’s Prism application project at work where I was recently tasked to improve the startup performance.

At this time, the project contains sixty-nine IModule implementation types; however, that number is continuing to grow. All of these modules will not be loaded at once and some of them may not be used/loaded at all. Some of them are conditionally loaded during runtime when certain criteria are met.

While watching the Initializing Modules video I found myself wondering if anything would change if I were to change these conditionally loaded modules InitializationMode from the default WhenReady to OnDemand. My reasoning behind this is because Brian Lagunas explains that WhenReady initializes modules as soon as possible or OnDemand when the application needs them in the video. Brian recommends using OnDemand if the module is not required to run, is not always used, and/or is rarely used.

I have a few concerns:

  1. Impacting features because the module is not loaded beforehand or the Module initialization is not done manually.
  2. No performance impact because this project handles module initialization itself to parallelize it instead of letting Prism manage it.

In the end, only benchmarking each option will provide information to make a decision. To do this I used JetBrains dotTrace, focusing on the timings for App.OnStartup, Bootstrapper.Run, Bootstrapper.ConfigureModuleCatalog, and Bootstrapper.InitializeModules. Since we try to load modules in parallel, I ended up adding the timing for this as well - otherwise, the timing may have appeared off.

Baseline - InitializationMode.WhenAvailable

The first step was to gather baseline metrics.

Profile #1Profile #2Profile #3Profile #4Profile #5MinAverageMedianMaxSTD
App.OnStartup584546874220454549734220485446875845551.6462635
Bootstrapper.Run5954398625983293277925983722329359541215.581013
Bootstrapper.ConfigureModuleCatalog11487673635111.51.5558.15111148385.1511911
Bootstrapper.InitializeModules184109117857171113.210918439.0404918
Asynchronous Module Initialization182122332311257125641821230023112571274.6590614

Not terrible, but not ideal. The application splash screen is displayed for about 4.5 seconds on average on a developer machine with only a few conditional modules enabled.

InitializationMode.OnDemand

With the baseline determined, a comparison can be made when switching the modules to be loaded OnDemand.

Profile #1Profile #2Profile #3Profile #4Profile #5MinAverageMedianMaxSTD
App.OnStartup5419396943915919549039695037.654195919733.0750575
Bootstrapper.Run2770219720172086223820172261.621972770266.0320281
Bootstrapper.ConfigureModuleCatalog408374340352388340372.437440824.40983408
Bootstrapper.InitializeModules143676969666682.86914330.1224169
Asynchronous Module Initialization1926163916991603163216031699.816391926117.3292802

All the Bootstrapper methods seemed to have improved, but overall the App.OnStartup took approximately the same amount of time.

Summary

There was an impact, but not in the overall startup time - which I find a little peculiar. It seems as though the overhead may have been shifted elsewhere in the startup process.

This may mean a hybrid approach to Bootstrapper.InitializeModules does have merits although not as much as I had hoped. Another option may be to change the Bootstrapper.ConfigureModuleCatalog to conditionally determine to add modules instead of applying a ‘safe’ default. Or perhaps I am diagnosing the wrong problem and should at other options - such as switching Dependency Injection frameworks.

In any case, I am going to discuss this as an option with my team - and see if additional testing can be done with more conditional modules enabled.