Other Posts in Optimization

  1. Cheap Profiler for C#/ASP.Net and Cool Link
  2. Small Changes, Big Speed Ups

Cheap Profiler for C#/ASP.Net and Cool Link

10/23/2008
First off, I'm not sure if you'll find this useful or not. To be honest there are a ton of profilers out there with support for Visual Studio 2008. In fact if you have Developer or VSTS, it's built into the system. I however have the Professional Edition and I'm cheap (I didn't even pay for Visual Studio, I got the Professional Edition by going to an event that Microsoft had where they were handing them out)... Plus getting a profiler that works well with C#/ASP.Net is a bit of a hassle. So I created my own:

ProfilerManager.cs

   1: /*
   2: Copyright (c) 2010 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System.Collections.Generic;
  24: using System.Text;
  25: using Utilities.DataTypes.Patterns.BaseClasses;
  26: #endregion
  27:  
  28: namespace Utilities.Profiler
  29: {
  30:     /// <summary>
  31:     /// Actual location that profiler information is stored
  32:     /// </summary>
  33:     public class ProfilerManager : Singleton<ProfilerManager>
  34:     {
  35:         #region Constuctors
  36:  
  37:         protected ProfilerManager()
  38:         {
  39:             Profilers = new List<ProfilerInfo>();
  40:         }
  41:  
  42:         #endregion
  43:  
  44:         #region Public Functions
  45:  
  46:         /// <summary>
  47:         /// Adds an item to the manager (used by Profiler class)
  48:         /// </summary>
  49:         /// <param name="FunctionName">Function name/identifier</param>
  50:         /// <param name="StartTime">Start time (in ms)</param>
  51:         /// <param name="StopTime">Stop time (in ms)</param>
  52:         public void AddItem(string FunctionName, int StartTime, int StopTime)
  53:         {
  54:             ProfilerInfo Profiler = Profilers.Find(x => x.FunctionName == FunctionName);
  55:             if (Profiler != null)
  56:             {
  57:                 int Time = (StopTime - StartTime);
  58:                 Profiler.TotalTime += Time;
  59:                 if (Profiler.MaxTime < Time)
  60:                     Profiler.MaxTime = Time;
  61:                 else if (Profiler.MinTime > Time)
  62:                     Profiler.MinTime = Time;
  63:                 ++Profiler.TimesCalled;
  64:                 return;
  65:             }
  66:             ProfilerInfo Info = new ProfilerInfo();
  67:             Info.FunctionName = FunctionName;
  68:             Info.TotalTime = Info.MaxTime = Info.MinTime = StopTime - StartTime;
  69:             Info.TimesCalled = 1;
  70:             Profilers.Add(Info);
  71:         }
  72:  
  73:         /// <summary>
  74:         /// Outputs the information to a table
  75:         /// </summary>
  76:         /// <returns>an html string containing the information</returns>
  77:         public override string ToString()
  78:         {
  79:             StringBuilder Builder = new StringBuilder();
  80:             Builder.Append("<table><tr><th>Function Name</th><th>Total Time</th><th>Max Time</th><th>Min Time</th><th>Average Time</th><th>Times Called</th></tr>");
  81:             foreach (ProfilerInfo Info in Profilers)
  82:             {
  83:                 Builder.Append("<tr><td>").Append(Info.FunctionName).Append("</td><td>")
  84:                     .Append(Info.TotalTime.ToString()).Append("</td><td>").Append(Info.MaxTime)
  85:                     .Append("</td><td>").Append(Info.MinTime).Append("</td><td>")
  86:                     .Append(((double)Info.TotalTime / (double)Info.TimesCalled)).Append("</td><td>")
  87:                     .Append(Info.TimesCalled).Append("</td></tr>");
  88:             }
  89:             Builder.Append("</table>");
  90:             return Builder.ToString();
  91:         }
  92:  
  93:         #endregion
  94:  
  95:         #region Private Properties
  96:         private List<ProfilerInfo> Profilers { get; set; }
  97:         #endregion
  98:  
  99:         #region Private Classes
 100:  
 101:         /// <summary>
 102:         /// Holds the profiler information
 103:         /// </summary>
 104:         private class ProfilerInfo
 105:         {
 106:             public string FunctionName;
 107:             public int TotalTime;
 108:             public int TimesCalled;
 109:             public int MaxTime;
 110:             public int MinTime;
 111:         }
 112:  
 113:         #endregion
 114:     }
 115: }

Profiler.cs

   1: /*
   2: Copyright (c) 2010 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24:  
  25: #endregion
  26:  
  27: namespace Utilities.Profiler
  28: {
  29:     /// <summary>
  30:     /// Object class used to profile a function.
  31:     /// Create at the beginning of a function and it will automatically record the time.
  32:     /// Note that this isn't exact and is based on when the object is destroyed
  33:     /// (if stop isn't called first that is) which leaves it up to garbage collection...
  34:     /// ie. call Stop...
  35:     /// </summary>
  36:     public class Profiler : IDisposable
  37:     {
  38:         #region Private Variables
  39:         private int StartTime = System.Environment.TickCount;
  40:         private int StopTime = System.Environment.TickCount;
  41:         private bool Running = true;
  42:         private string Function = "";
  43:         #endregion
  44:  
  45:         #region Constructors
  46:  
  47:         /// <summary>
  48:         /// Constructor
  49:         /// </summary>
  50:         public Profiler()
  51:         {
  52:         }
  53:  
  54:         /// <summary>
  55:         /// Constructor
  56:         /// </summary>
  57:         /// <param name="FunctionName">Takes in the function name/identifier</param>
  58:         public Profiler(string FunctionName)
  59:         {
  60:             Function = FunctionName;
  61:         }
  62:  
  63:         #endregion
  64:  
  65:         #region Public Functions
  66:  
  67:         /// <summary>
  68:         /// Disposes of the object
  69:         /// </summary>
  70:         public virtual void Dispose()
  71:         {
  72:             Stop();
  73:         }
  74:  
  75:         /// <summary>
  76:         /// Stops the timer and registers the information
  77:         /// </summary>
  78:         public virtual void Stop()
  79:         {
  80:             if (Running)
  81:             {
  82:                 Running = false;
  83:                 StopTime = System.Environment.TickCount;
  84:                 ProfilerManager.Instance.AddItem(Function, StartTime, StopTime);
  85:             }
  86:         }
  87:  
  88:         #endregion
  89:     }
  90: }

That should be two classes, one being the Profiler class and one being the Manager. The Profiler class is what actually measures the time that a function takes. All you do is create a new Profiler object at the point that you want to start timing, and then call Stop when you want to stop (since it's disposable, you can simply put it in a using statement if you'd prefer to ensure that Stop is called). The Manager class is a singleton (one of the few instances where a singleton makes sense) and all it does is store the information from the Profiler class. The singleton base class is a part of my utility library and can be found there (this code can also be found in the library, which will have the most up to date version). The Manager class records the maximum amount of time for that function, average minimum amount of time, total time, and number of times it was called. If I wanted to get fancy, I could have it hook directly into the app and profile that way but I just needed something simple. You might find it useful, I don't know, but try it out and leave feedback.

Also, I've been talking a bit about Microformats (XFN, hCard, etc.) and I found an interesting link that I think you'll find useful with regard to Microformats. It's a cheat sheet for most of the formats that you'll run into (with a couple of exceptions like XOXO, etc.) So if you're interested in implementing Microformats into your own site, definitely give that link a look.



Comments