Starting CMS 6 R2 sites faster after build
About a year ago I wrote a very popular blog post about how to start a CMS 6 site faster after a build and since then it has been read almost 3,000 times. After discussing the issue of start up speed a lot lately, I thought it was time to write an update. This blog post will show you how to start an EPiServer CMS 6 R2 site faster, and the tips will also speed up EPiServer Commerce and EPiServer Relate.
Why…. is…. it… so…. slow….
Starting an EPiServer CMS site after a build used to take forever on the hardware of the day (remember the epi demo site taking 1 minute to load on my old WinXP laptop). Now however speed has increased due to newer hardware (i7/8GB RAM/SSD) and improvements in the CMS 6 R2 release. However on a big EPiServer CMS project, and especially if you use Commerce and/or Relate it still can take quite a while to load. So any improvements in start up speed is much welcomed.
Lets make it faster!
By following these 4 tips you can make your EPiServer CMS 6 R2 site start faster (it will also work on R1). They will also greatly improve performance of a Commerce and/or Relate site.
I have tested on two different projects:
-Test A: EPiServer CMS 6 R2 with the Alloy Tech demo site
-Test B: A real life Making Waves project building an intranet for a customer using EPiServer CMS 6 R2 and EPiServer Relate 2.0 R2.
Test A: EPiServer CMS 6 R2 with Alloy tech demo
The startup time for the EPiServer Alloy Tech demo was initially 7.48 seconds. By applying each of the 4 tips our test shows the startup time falling to about 1 second.
Test B: Intranet site with EPiServer CMS 6 R2 and EPiServer Relate 2.0 R2
The startup time for this project was on average 71 seconds before we started applying the tips. The biggest effect came from optimizing the compilations that resulted in a 60 second cut! The final result was start up time of about 7 seconds, a 90% reduction!
Tip 1: Use EPiServer CMS 6 R2 (or remove lang files)
And old trick was to delete all the xml language files you didn’t need in the lang folder to improve start up time. But as of R2 EPiServer has moved the language strings into resource files turning 67 lang files into only 15. So make sure you use CMS 6 R2. (If you have to use R1, then of course delete the lang files you don’t need in the lang folder)
Tip 2: Optimize compilations
By default, when any change is made to a top-level file (global.asax and all files in bin and App_Code) in a Web site, the whole site is recompiled. It is safest to recompile everything when one of these files changes because other files in the site, such as .aspx and .ascx files, may reference the objects created by code in top-level files.
By adding optimizeCompilations="true" to the compilation tag we can improve the start up performance of our site considerably, but you might experience run-time errors if you delete, rename or change the signature of a method referenced by an already-compiled page. If this happens simply set it to false, rebuild and then set it to true again. More info.
Note: You will not see any improvements the first time you start the site after build after setting this to true, but the second time. (It needs to generate some hashes the first time).
Open web.config and fine this line:
<compilation defaultLanguage="c#" debug="true">
Add the following attribute: optimizeCompilations="true"
<compilation defaultLanguage="c#" debug="true" optimizeCompilations="true">
By just doing this simple change we improve the startup performance with 2 seconds on our Alloy demo site and 60 seconds for our Relate 2.0 R2 project!
Recommendation:
The tests shows that this is definitely worth doing. Just keep in mind that if you see some runtime errors just set it to false, rebuild and then set it to true again. Recommended.
Tip 3: Prevent scanning of know assemblies
When EPiServer CMS 6 R2 is started it scans all the assemblies in the bin folder for stuff to initialize and EPiServer plugins. This takes a long time, and by telling EPiServer what assemblies does not need scanning we can reduce the warm up time. We can do this by adding the names of assemblies that does not need scanning to the EPiServerFramework.config. But how do we know what assemblies doesn’t need scanning? EPiOptimizer to the rescue!
Find assemblie to exclude with EPiOptimizer
I will show you how to integrate EPiOptimizer into Visual Studio, but you can also include it into the build process. (it will generate a build error if it finds an assembly you can safely exclude that you haven’t added to the ignore list).
Step 1: Download EPiOptimizer.exe to c:\Tools\
Step 2: In Visual Studio go to Tools –> External Tools…
Click the “Add” button. Set the Title to “EPiOptimizer”, Command to the path of your EPiOptimizer.exe file and Arguments to: $(ProjectDir)web.config Make sure to check the box “Use Output window”.
Step 3: Open your EPiServer project and run the EPiOptimzer tool: Tools –> EPiOptimizer
EPiOptimizer will now scan your project and list the assemblies you can safely exclude from scanning in the ouput window. These are also copied to your clipboard.
Step 4: Open EPiServerFramework.config
It will look something like this:
<episerver.framework>
<scanAssembly forceBinFolderScan="true" />
...
</episerver.framework>
Set forceBinFolderScan to false, and paste the assemblies from EPiOptimizer into the <scanAssembly> tag. When you are done it should look something like this:
<episerver.framework>
<scanAssembly forceBinFolderScan="false">
<add assembly="*" />
<remove assembly="DocumentFormat.OpenXml" />
<remove assembly="ElektroPost.Licensing" />
<remove assembly="EPiServer.BaseLibrary" />
<remove assembly="EPiServer.Configuration" />
<remove assembly="EPiServer.Data.Cache" />
<remove assembly="EPiServer.ImageLibrary" />
<remove assembly="EPiServer.Implementation" />
<remove assembly="EPiServer.Legacy4" />
<remove assembly="EPiServer.Licensing" />
<remove assembly="EPiServer.Log.Analyzers" />
<remove assembly="EPiServer.Log.Core" />
<remove assembly="EPiServer.Lucene" />
<remove assembly="EPiServer.Scheduler" />
<remove assembly="EPiServer.Scheduler.WKTL" />
<remove assembly="EPiServer.Web.WebControls" />
<remove assembly="EPiServer.WebDav" />
<remove assembly="EPiServer.WebParts" />
<remove assembly="EPiServer.XForms" />
<remove assembly="EPiServer.XmlRpc" />
<remove assembly="log4net" />
<remove assembly="Microsoft.Web.Services3" />
<remove assembly="System.ComponentModel.Composition" />
<remove assembly="System.Web.DataVisualization" />
<remove assembly="System.Web.Mvc" />
</scanAssembly>
...
</episerver.framework>
Save the file. In our Alloy tech demo test this shaves of about 1 second of the start up time.
Note: If you upgrade your solution to a newer version of EPiServer, write a EPiServer plugin (EPiServer.PlugIn.PlugInAttribute) or add code that requires initialization, make sure to redo these steps.
Recommendation:
The tests shows that this is only shaves of a second or two of the startup time. It is probably not worth doing unless you have a huge project.
Tip 4: Use WarmMeUp.exe to start the site after build
This tip will not actually make your site start faster (it will take just as long no matter how you do it), but it will shave some seconds off as you switch to your browser and reload the page you are working on. And the best part is that you don’t need to rush to reload the page to get the site warmed up.
WarmMeUp.exe is a tiny (6KB), open source tool I wrote that simply pings a URL asynchronously, and by adding it to your project’s post-build event it will make your site nice and toasty for you
How to add WarmMeUp to your project using Nuget
Follow these instructions to add WarmMeUp using Nuget. You can also install it manually.
Step 1: Install MakingWaves.WarmMeUp using EPiServer’s Nuget feed
Step 2: Open your project and go to properties (right click the project in "Solution Explorer" and choose properties)
Click the "Build Events" tab and add the following line in the "Post-buil event command line:" text box:
$(ProjectDir)WarmMeUp\WarmMeUp.exe http://localhost/
Step 3: Change http://localhost/ to the url you want to warm up and save.
Recommendation:
This easily shaves 3-4 seconds of your startup time and is very convenient as well since you don’t need to rush to refresh the page to get the site warmed up. Highly recommended.
Rebuild your project and see if it is faster
Now rebuild your project and see if it starts any faster.
In these tests I have used this simple HTML file to do the timings: Download Timer.htm
Final recommendations
It is clear that you can easily do something to improve the startup time of your EPiServer project. Going from 7 to 1 second for an EPiServer site might not be much, but as test B shows, you can save an entire minute of startup time on a Relate site! My recommendation is that you use CMS 6 R2 with optimizeCompilations="true" and add WarmMeUp in your post-build events.
Falcon will be even faster!
EPiServer is hard at work on the next version of EPiServer CMS and I know they are working on cutting the build time even further. Yay!
Feedback
I appreciate your feedback on this blog post, especially if you know any more tricks to speed things up. Please comment below or tweet: @ahaneng
Posted by Alexander Haneng
Nice one! All tricks that can speed up start-up time is welcomed. I had totally forgotten about that optimizeCompilations switch. Per Bjurström blogged about this in 2009.
Your WarmMeUp nuget package should set that switch to true by default :-)
Great tips Alexander!
Thanks for sharing this, the timer was a clean and simple solution to measuring.
Hi Alexander, great article not sure if it'll make your warmup module redundant but have
you tried the auto-start feature of IIS 7.5 / Asp.net 4 described here: http://weblogs.asp.net/scottgu/archive/2009/09/15/auto-start-asp-net-applications-vs-2010-and-net-4-0-series.aspx ?