Anders Hattestad
Jun 5, 2012
  3689
(0 votes)

Log how long a page takes to generate

After a project goes live there is often some debate if the site is fast enough. With today’s heavy use of JavaScript a lot is done after the page is loaded so it’s difficult for a user to actually know if it’s the rendering/JavaScript or the page generating that takes time.

In a project of mine we had terrible lag, and load time experienced for the users was very high. I wrote a small report that saved hourly the count of load time grouped by 1,2,3,4,5+ seconds.

image

After I had let that code run for some hours I saw that the generating time from the server was not the problem. The actually problem was that the client didn’t cache the image resource files that were in use. I had overlooked the new (?) section in IIS7, so I changed my web.config to

    <caching>
      <profiles>
        <add extension=".gif" policy="CacheForTimePeriod" kernelCachePolicy="DontCache" duration="01:01:00" location="Any" />
        <add extension=".png" policy="CacheForTimePeriod" kernelCachePolicy="DontCache" duration="01:01:00" location="Any" />
        <add extension=".js" policy="CacheForTimePeriod" kernelCachePolicy="DontCache" duration="01:01:00" location="Any" />
        <add extension=".css" policy="CacheForTimePeriod" kernelCachePolicy="DontCache" duration="01:01:00" location="Any" />
        <add extension=".jpg" policy="CacheForTimePeriod" kernelCachePolicy="DontCache" duration="01:01:00" location="Any" />
        <add extension=".jpeg" policy="CacheForTimePeriod" kernelCachePolicy="DontCache" duration="01:01:00" location="Any" />
      </profiles>
    </caching>

And the clients got a huge boost in load time.

The little plugin works like this:

In my master page I added this code to Render

Code Snippet
  1. public partial class UDMaster : System.Web.UI.MasterPage,IHaveProperties
  2. {
  3.     DateTime start = DateTime.Now;
  4.  
  5.     protected override void Render(HtmlTextWriter writer)
  6.     {
  7.         if (PageTimesGrouped.SavePageTimesGrouped())
  8.         {
  9.             PageTimesGrouped.Add(((TimeSpan)(DateTime.Now - start)));
  10.         }
 
The Dynamic DataStore class looks like this. I save only one row pr hour so this code will not generate a lot of rows. It will only save down to the DDS base if it gets a request for a new hour. 
Code Snippet
  1. [EPiServerDataStore(AutomaticallyRemapStore = true, AutomaticallyCreateStore = true)]
  2. public class PageTimesGrouped : BaseData<PageTimesGrouped>
  3. {
  4.         [EPiServerDataIndex]
  5.     public DateTime Date { get; set; }
  6.  
  7.     public int Bellow1s { get; set; }
  8.     public int Count_1s_2s { get; set; }
  9.     public int Count_2s_3s { get; set; }
  10.     public int Count_3s_4s { get; set; }
  11.     public int Count_4s_5s { get; set; }
  12.     public int Above5s { get; set; }
  13.  
  14.        
  15.     static PageTimesGrouped _currentTime;
  16.     public static PageTimesGrouped CurrentTime()
  17.     {
  18.         var now = DateTime.Now;
  19.         if (_currentTime == null)
  20.         {
  21.             _currentTime = new PageTimesGrouped() { Date = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0), Bellow1s = 0, Count_1s_2s = 0, Count_2s_3s = 0, Count_3s_4s = 0, Count_4s_5s = 0, Above5s = 0 };
  22.         }
  23.         if (_currentTime.Date.Hour != now.Hour)
  24.         {
  25.             _currentTime.Save();
  26.             _currentTime = new PageTimesGrouped() { Date = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0), Bellow1s = 0, Count_1s_2s = 0, Count_2s_3s = 0, Count_3s_4s = 0, Count_4s_5s = 0, Above5s = 0 };
  27.         
  28.         }
  29.         return _currentTime;
  30.     }
  31.     public static void Add(TimeSpan span)
  32.     {
  33.         try
  34.         {
  35.             var a = CurrentTime();
  36.             if (span.TotalMilliseconds < 1000)
  37.                 a.Bellow1s++;
  38.             else if (span.TotalMilliseconds < 2000)
  39.                 a.Count_1s_2s++;
  40.             else if (span.TotalMilliseconds < 3000)
  41.                 a.Count_2s_3s++;
  42.             else if (span.TotalMilliseconds < 4000)
  43.                 a.Count_3s_4s++;
  44.             else if (span.TotalMilliseconds < 5000)
  45.                 a.Count_4s_5s++;
  46.             else
  47.                 a.Above5s++;
  48.         }
  49.         catch { }
  50.     }
  51.     public static bool SavePageTimesGrouped()
  52.     {
  53.         string tmp = System.Web.Configuration.WebConfigurationManager.AppSettings.Get("SavePageTimesGrouped");
  54.         if (!string.IsNullOrEmpty(tmp))
  55.             return true;
  56.         return false;
  57.     }
  58.     public decimal RequestPrMin
  59.     {
  60.         get
  61.         {
  62.             var count = Bellow1s + Count_1s_2s + Count_2s_3s + Count_3s_4s + Count_4s_5s + Above5s;
  63.             var now = DateTime.Now;
  64.             var naa = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0);
  65.             if (Date > now.AddHours(1))
  66.                 return count / (60);
  67.             var a = now.Minute - Date.Minute;
  68.             if (a > 0)
  69.                 return count / a;
  70.             return -1;
  71.         }
  72.     }
  73.  
  74. }
 The Report plugin looks like this

Code Snippet
  1. [GuiPlugIn(
  2.     Area = PlugInArea.ReportMenu,
  3.     DisplayName = "ShowPageInfo grouped",
  4.     Url = "~/Custom/AdminPages/ShowPageTimesV2.aspx")]
  5. public partial class ShowPageTimesV2 : System.Web.UI.Page
  6. {
  7.     protected void Page_Load(object sender, EventArgs e)
  8.     {
  9.         Bind();
  10.     }
  11.  
  12.     void Bind()
  13.     {
  14.         CurrentList.DataSource = new object[] { PageTimesGrouped.CurrentTime() };
  15.         CurrentList.DataBind();
  16.         List2.DataSource = (from item in PageTimesGrouped.Items orderby item.Date descending select item).Take(100);
  17.         List2.DataBind();
  18.     }
  19. }

with front code like this

Code Snippet
  1. <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ShowPageTimesV2.aspx.cs" Inherits="UDFase1.Custom.AdminPages.ShowPageTimesV2" %>
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml">
  4. <body>
  5.     <form id="form1" runat="server">
  6.     <div>
  7.    SavePageTimesGrouped=<%=Itera.Data.PageTimesGrouped.SavePageTimesGrouped()%><br />
  8.    
  9.    <asp:Literal ID="DebugLit" runat="server" />
  10.  
  11.     <table border="1">
  12.                 <tr>
  13.                     <th>Dato</th>
  14.                     <th>Less 1s</th>
  15.                     <th>1s-2s</th>
  16.                     <th>2s-3s</th>
  17.                     <th>3s-4s</th>
  18.                     <th>4s-5s</th>
  19.                     <th>Abvoe 5s</th>
  20.                 </tr>
  21.  
  22.      <asp:Repeater ID="CurrentList" runat="server">
  23.  
  24.         <ItemTemplate>
  25.             <tr>
  26.                 <td><%#Eval("Date") %></td>
  27.                <td><%#Eval("Bellow1s")%></td>
  28.                 <td><%#Eval("Count_1s_2s")%></td>
  29.                 <td><%#Eval("Count_2s_3s")%></td>
  30.                 <td><%#Eval("Count_3s_4s")%></td>
  31.                 <td><%#Eval("Count_4s_5s")%></td>
  32.                 <td><%#Eval("Above5s")%></td>
  33.                 <td><%#Eval("RequestPrMin") %></td>
  34.  
  35.             </tr>
  36.         </ItemTemplate>
  37.      
  38.     </asp:Repeater>
  39.  
  40.  
  41.      <asp:Repeater ID="List2" runat="server">
  42.       
  43.         <ItemTemplate>
  44.             <tr>
  45.                 <td><%#Eval("Date") %></td>
  46.                <td><%#Eval("Bellow1s")%></td>
  47.                 <td><%#Eval("Count_1s_2s")%></td>
  48.                 <td><%#Eval("Count_2s_3s")%></td>
  49.                 <td><%#Eval("Count_3s_4s")%></td>
  50.                 <td><%#Eval("Count_4s_5s")%></td>
  51.                 <td><%#Eval("Above5s")%></td>
  52.                 <td><%#Eval("RequestPrMin") %></td>
  53.  
  54.             </tr>
  55.         </ItemTemplate>
  56.  
  57.     </asp:Repeater>
  58.      </table>
  59.     
  60.                           
  61.       
  62.     </div>
  63.     </form>
  64. </body>
  65. </html>

Jun 05, 2012

Comments

Jun 6, 2012 03:52 PM

Hi,

Can you please provide BaseData class as well.

Thanks

Anders Hattestad
Anders Hattestad Jun 6, 2012 10:29 PM

Hi

Sorry for that. The base class is in this post
http://world.episerver.com/Blogs/Anders-Hattestad/Dates/2012/5/Cache-Dynamic-Data-Store-items/

Please login to comment.
Latest blogs
Opti ID overview

Opti ID allows you to log in once and switch between Optimizely products using Okta, Entra ID, or a local account. You can also manage all your use...

K Khan | Jul 26, 2024

Getting Started with Optimizely SaaS using Next.js Starter App - Extend a component - Part 3

This is the final part of our Optimizely SaaS CMS proof-of-concept (POC) blog series. In this post, we'll dive into extending a component within th...

Raghavendra Murthy | Jul 23, 2024 | Syndicated blog

Optimizely Graph – Faceting with Geta Categories

Overview As Optimizely Graph (and Content Cloud SaaS) makes its global debut, it is known that there are going to be some bugs and quirks. One of t...

Eric Markson | Jul 22, 2024 | Syndicated blog

Integration Bynder (DAM) with Optimizely

Bynder is a comprehensive digital asset management (DAM) platform that enables businesses to efficiently manage, store, organize, and share their...

Sanjay Kumar | Jul 22, 2024

Frontend Hosting for SaaS CMS Solutions

Introduction Now that CMS SaaS Core has gone into general availability, it is a good time to start discussing where to host the head. SaaS Core is...

Minesh Shah (Netcel) | Jul 20, 2024

Optimizely London Dev Meetup 11th July 2024

On 11th July 2024 in London Niteco and Netcel along with Optimizely ran the London Developer meetup. There was an great agenda of talks that we put...

Scott Reed | Jul 19, 2024