[To learn more about the Sitefinity performance, check the performance whitepaper and webinar]
Working with a product for many years there is always something that irritates you at least a little :). We can all agree that this view is quite familiar to all Sitefinity developers and we want to spend less time with it:
Sitefinity 10.1 boosts the startup performance phase of Sitefinity websites and cuts the time in half in many cases—and for large sites, the improvement can be even greater. When your application starts for the first time and it is optimized according to best practices, the time spent with the “Please wait a moment” screen should be significantly decreased. That performance improvement is noticeable even without complex measurements.
Before we deep dive into details about the performance components of a Sitefinity website’s life cycle and ASP.NET, let’s take look at some results with Sitefinity 10.1.
Empty Web App |
||
From 22.75 sec |
To 11.91 sec |
Startup time reduced by 47.63% |
Telerik.com |
||
From 45.56 sec |
To 21.54 sec |
Startup time reduced by 52.71% |
Progress.com |
||
From 34.20 sec |
To 18.90 sec |
Startup time reduced by 44.73% |
Sitefinity.com |
||
From 49.64 sec |
To 18.74 sec |
Startup time reduced by 62.24% |
Large customers’ website |
||
From 54.05 sec |
To 19.52 sec |
Startup time reduced by 63.89% |
Huge customers’ website |
||
From 131.64 sec |
To 26.32 sec |
Startup time reduced by 80.01% |
It is very important to understand the ASP.NET Application startup flow, because this will help us to measure our performance in details. The whole process can be divided into three main phases.
The first phase is the update of the Temporary ASP.NET Folder. It is executed after rebuild, deployment or other changes in the bin folder of your project. By default, it clears everything from the Temporary ASP.NET Folder, and copies the new files there.
The second is the Web Application Initialization, which can be divided into three sub-steps. The Applications Start stage where custom code is executed on application start (e.g.: in global.asax, in assemblies with PreApplicationStartMethod attribute, etc.), the Sitefinity Startup stage and then finally the Sitefinity Bootstrap events that custom handlers are executed on.
The last phase is the initial page load. This is the time when the first page request causes the application to start. If the page is not already compiled in the Temporary ASP.NET Folder, it will be dynamically compiled. For more details look at Understanding ASP.NET Dynamic Compilation.
The following diagram describes all the phases including the processes running after the project has been compiled and started.
From the above list with startup phases we optimized the Sitefinity Startup (phase 2), as this is the part we have the most control of. For most common scenarios, the total startup time is reduced by half. For big projects (with many dynamic types, sites, languages), the improvement is even more significant. Along with reducing the time of the startup, we also made it more stable and less dependent of the size of the project (modules, languages, sites, dynamic types, custom fields).
While Sitefinity out-of-the-box modules are already optimized, the startup could be compromised by a custom module which consumes a lot of time to initialize and load.
Therefore, we provide a way to diagnose the startup process and identify the bottlenecks. This can be done with the following setting in the web.config:
<
appSettings
>
...
<
add
key
=
"sf:methodPerformanceLoggingPath"
value
=
"~/App_Data/Sitefinity/Logs"
/>
Thus, log files starting with “data-” prefix are generated in the specified folder.
You could also measure the performance of your own implementation by wrapping some code in MethodPerformanceRegion:
using
(
new
MethodPerformanceRegion(
"My Initialization Code"
))
{
// My potentially slow implementation
}
This way, your method time will be displayed in the “data-“ log files.
It is very important to use the above method performance logging technique to diagnose the whole website performance and custom implementations, and not only the startup. This will help you have more accurate measurements about your performance and will give you a clue as to what could be improved.
The first thing is to upgrade to 10.1, as there is a huge improvement in the Sitefinity Startup phase regarding performance, stabilization and diagnostics. Both your production and development performance will benefit from it. Next, use the Roslyn compiler—we measured that the compilation with Roslyn is a about six times faster than using the default compiler. As side note, we are not currently aware of any issues with Roslyn. You can find more details here.
Another very simple but effective approach for performance optimizations on production and development environment is to turn on warmup and caching in production, but disable them on your development machine.
The most time consuming part of the website is the dynamic compilation of pages and widget templates. Every time a page or widget template is loaded for the first time, it is compiled. And every time you rebuild the project all compiled pages and templates are deleted, even though they are not changed. Why not keep the previous compilations, since they are not changed, and save some time? This can be done with optimizeCompilations web.config setting:
<
compilation
optimizeCompilations
=
"true"
>
It is outlined in the following article. In short, with this option the Temporary ASP.NET Files will not be deleted after compiling the project. Only the modified assemblies will be replaced. So, the dynamically compilated pages and widget templates won’t be deleted as well. Thus, when you load the same page and widgets after rebuilding the project, they will be taken from Temporary ASP.NET Files, instead of compiling them again, and the page will be loaded faster.
When a compiled widget template is loaded in the application by requesting a page containing it, it has a cache dependency to the physical file of the template, so when the files are changed, the compiled template is invalidated, and the new version will be precompiled when you load the widget next time. However, if you change a template of a widget, which is still not loaded (never been accessed since the application start), its compilation version won’t be invalidated. Therefore, next time when you load the widget template, you might load a version which is not up-to-date.
This problem might appear even without optimizeCompilations, but very rarely, because each rebuild deletes all dynamically precompiled templates. With optimizeCompilations, it may happen more often.
Therefore, with the optimizeCompilations option it is recommended to manually clean up the Temporary ASP.NET Files, when you need to ensure that all templates are up-to-date.
For easy maintaining Temporary ASP.NET Files, you can change its default location:
<
compilation
tempDirectory
=
"C:\\ASPNET_Temp"
>
Additionally, if your hard disk is not SSD, you can optimize Temporary ASP.NET Files synchronization by mapping a part of the RAM to a virtual drive and use it as a tempDirectory. You can find more details about this in the following post.
The easiest way to see an immediate performance improvement in your Sitefinity application is to upgrade to version 10.1. Be aware that we improved one piece of the big puzzle (among many more updates, which you can see in the full release notes), but there are many other components that should be measured and analyzed. To identify the areas that could be improved, use the above approaches to gain insights into how your code performs. We are curious about your new performance results—don’t be shy and share them in the comments.
View all posts from Vladimir Vasilev on the Progress blog. Connect with us about all things application development and deployment, data integration and digital business.
Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.
Learn MoreSubscribe to get all the news, info and tutorials you need to build better business apps and sites