Anders Hattestad
Jun 5, 2012
  3181
(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
Plug-in manager is back in CMS 12

Plug-in manager is back in the UI, what is it and how can i use it?

Luc Gosso (MVP) | Oct 6, 2022 | Syndicated blog

Display Child Pages in Content Delivery API Response

The below example will implement an instance of IContentConverterProvider to customise the serialisation of PageData and output child pages in the...

Minesh Shah (Netcel) | Oct 4, 2022

Bring the Report Center back in Optimizely CMS 12

The Report Center has been a part of Optimizely CMS since its first debut in version 5R2 in 2008, but in CMS 12, it's removed! Don't despair! Make...

Tomas Hensrud Gulla | Oct 4, 2022 | Syndicated blog

Customizing Property Lists in Optimizely CMS

Generic property lists is a cool editorial feature that has gained a lot of popularity - in spite of still being unsupported (officially). But if y...

Allan Thraen | Oct 2, 2022 | Syndicated blog