Try our conversational search powered by Generative AI!

Anders Hattestad
Jun 5, 2012
  3663
(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
Optimizely and the never-ending story of the missing globe!

I've worked with Optimizely CMS for 14 years, and there are two things I'm obsessed with: Link validation and the globe that keeps disappearing on...

Tomas Hensrud Gulla | Apr 18, 2024 | Syndicated blog

Visitor Groups Usage Report For Optimizely CMS 12

This add-on offers detailed information on how visitor groups are used and how effective they are within Optimizely CMS. Editors can monitor and...

Adnan Zameer | Apr 18, 2024 | Syndicated blog

Azure AI Language – Abstractive Summarisation in Optimizely CMS

In this article, I show how the abstraction summarisation feature provided by the Azure AI Language platform, can be used within Optimizely CMS to...

Anil Patel | Apr 18, 2024 | Syndicated blog

Fix your Search & Navigation (Find) indexing job, please

Once upon a time, a colleague asked me to look into a customer database with weird spikes in database log usage. (You might start to wonder why I a...

Quan Mai | Apr 17, 2024 | Syndicated blog