Click here to Skip to main content
15,886,199 members
Articles / Programming Languages / C#

Quick Performance Triage

Rate me:
Please Sign up or sign in to vote.
4.85/5 (14 votes)
3 Nov 2009CPOL6 min read 33.4K   202   33  
Class to help triage performance problems in your application
using System;
using System.Data;
using System.Configuration;
using System.Diagnostics;

namespace DiagnosticTools
{
    /// <summary>
    /// Method definition for having the log information handled in a custom way.
    /// </summary>
    /// <param name="isEnd">True if the task is ending. False if the task is starting.</param>
    /// <param name="taskName">The name of the task.</param>
    /// <param name="category">The category of the task.</param>
    /// <param name="elapsedTime">The elapsed time for the task when ending. If the task is just starting then a blank TimeSpan is provided and should be disregarded.</param>
    public delegate void CustomLog(bool isEnd, string taskName, string category, TimeSpan elapsedTime);

    /// <summary>
    /// A class for doing simple and straight forward performance monitoring.
    /// Designed to be very easy to drop in, use, and remove.
    /// When used in a debug session in the IDE, the information will be written to the 
    /// Output tab in the Debug section.
    /// </summary>
    /// <remarks>
    /// To enable this in an ASP.NET web service, some changes to the web.config file are required.
    /// </remarks>
    /// <example>
    /// An example of a simple use.
    /// <code>
    /// using (new SimpleTimer("Write invoice to DB"))
    /// {
    ///     // task to measure performance on.
    /// }
    /// </code>
    /// This example shows how it can be nested.
    /// <code>
    /// using (new SimpleTimer("Top Level Task 1"))
    /// {
    ///     // Some code that may take time
    /// 
    ///     using (new SimpleTimer("Nested Task 2"))
    ///     {
    ///         // task to measure performance on.
    ///     }
    /// }
    /// </code>
    /// </example>
    public class SimpleTimer : IDisposable
    {
        #region Private Members
        private string _TaskName;
        private string _Category;
        //http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx
        private Stopwatch _Stopwatch = new Stopwatch();
        private CustomLog _LoggingMethod;
        #endregion

        #region Constructors

        /// <summary>
        /// Start a timer with a task name assigned.
        /// </summary>
        /// <param name="taskName">The name of the task being measured.</param>
        public SimpleTimer(string taskName) : this(taskName, null) { }

        /// <summary>
        /// Start a timer with a task name assigned.
        /// </summary>
        /// <param name="taskName">The name of the task being measured.</param>
        /// <param name="category">The category or group name for the task.</param>
        public SimpleTimer(string taskName, string category) : this(taskName, category, null) { }

        /// <summary>
        /// Start a timer with a task name assigned.
        /// </summary>
        /// <param name="taskName">The name of the task being measured.</param>
        /// <param name="category">The category or group name for the task.</param>
        /// <param name="log">The delegated method to log information to.</param>
        public SimpleTimer(string taskName, string category, CustomLog log)
        {
            if (String.IsNullOrEmpty(taskName))
                throw new ArgumentException("taskName is null or empty.", "taskName");

            _TaskName = taskName;
            // Use "SimpleTimer" if they don't provide a category to use.
            _Category = (String.IsNullOrEmpty(category))? "SimpleTimer" : category;

            // Use default Trace logging if one isn't provided.
            _LoggingMethod = (log != null)? log : TraceLog;

            // Notify that the task is about to begin.
            _LoggingMethod(false, _TaskName, _Category, new TimeSpan());
            _Stopwatch.Start();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Get the text description of the task being timed.
        /// </summary>
        public string TaskName
        {
            get
            {
                return _TaskName;
            }
        }

        /// <summary>
        /// Get the category assigned for the timer.
        /// </summary>
        public string Category
        {
            get
            {
                return _Category;
            }
        }
        #endregion

        #region IDisposable Members

        /// <summary>
        /// Stops the timer and outputs the information.
        /// </summary>
        public void Dispose()
        {
            StopTimerAndOutput();
        }

        #endregion

        #region Private Methods

        // Default handler for logging information to the "Trace" output.
        private void TraceLog(bool isEnd, string taskName, string category, TimeSpan elapsedTime)
        {
            if (isEnd)
            {
                Trace.Unindent();

                // Record the time formatted in milliseconds
                string timeText = String.Format("{0} msec", elapsedTime.TotalMilliseconds);

                // Write out that the closing information with time details
                Trace.WriteLine(String.Format("{0} - End - ({1})", taskName, timeText), category);

                // Ensure the data is written out
                Trace.Flush();
            }
            // else is start
            else
            {
                // Write out that we are starting
                Trace.WriteLine(String.Format("{0} - Start", taskName), category);

                Trace.Indent();
            }
        }
        
        /// <summary>
        /// Stop the timer and write out the information on elapsed time.
        /// </summary>
        private void StopTimerAndOutput()
        {
            // First, stop the timer.
            _Stopwatch.Stop();

            // Notify that the task has ended and pass in the elapsed time.
            _LoggingMethod(true, _TaskName, _Category, _Stopwatch.Elapsed);
        }
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
United States United States
Mark Ericksen is a Senior Developer, Technical Lead, Architect and more. He is passionate about technology, photography, and continually learning.

Comments and Discussions