Wednesday, July 28, 2004

The next version of MbUnit (2.20) will have a new custom attribute that will let you assert on the values of PerformanceCounters: PerfCounterAttribute. (Idea suggested by ISerializable). This means that you can make an assertion an every perfomance counter on your machine!

Here's a sample fixture that shows how the attribute can be used:

using System;
using MbUnit.Core.Framework;
using MbUnit.Framework;
namespace MbUnit.Demo
{
  [TestFixture]
  public class PerfCounterDemo
  {
    [Test]
    [PerfCounter(".NET CLR Memory", "% Time in GC", 10)]
    public void AllocateALotOfObjects()
    {
      ...
    }

    [Test]
    [PerfCounter(".NET CLR Loading", "% Time Loading", 10)]
    [PerfCounter(".NET CLR Security", "% Time in RT checks", 10000)]
    [PerfCounter(".NET CLR Security", "% Time Sig. Authenticating", 10)]
    [PerfCounter(".NET CLR Memory", "# Bytes in all Heaps", 5000000, Relative =true)]
    [PerfCounter(".NET CLR Jit", "% Time in Jit", 10)]
    public void MonitorMultipleCounters()
    {
      ...
    }
  }
}

Note that if you are too lazy to remember the names of the counters, I have written a CodeSmith template that creates a class filled with static helper methods for retreiving the counters. For example, the following class lets you write things like PerfCounterInfo.NetClrExceptions.NbofExcepsThrown.NextValue() using intellisense and without typing errors :)

using System;
using System.Diagnostics;
namespace MbUnit.Core.Framework
{
 public class PerfCounterInfo
 {  
  public sealed class NetClrExceptions
  {
   const string categoryName = @".NET CLR Exceptions";

   public sealed class NbofExcepsThrown
   {
    const string counterName = @"# of Exceps Thrown";

    public static float NextValue()
    {
     return NextValue(Process.GetCurrentProcess().ProcessName);
    }    
   }
   ...
posted on Thursday, July 29, 2004 5:29:00 AM UTC  #    Comments [8]
Tracked by:
http://www.google.com/search?q=mwinyplq [Pingback]
"100 debt elimination" (online) [Trackback]
Monday, June 06, 2005 5:41:43 PM UTC
Very nice.. How would I use the template to create the class? Does it only rely on <a title="CodeSmith" href="http://www.ericjsmith.net/codesmith/" target="_blank">CodeSmith</a>?
<br>
<br>Sorry for all the questions but all of your <a title="CodeSmith" href="http://www.ericjsmith.net/codesmith/" target="_blank">CodeSmith</a> templates confuse me.
<br>
<br>Thanks
Jerrad Anderson
Monday, June 06, 2005 5:41:44 PM UTC
Just double click on the template, select the Categories you want, and hit generate. Here's the latest source:
<br>
<br>&lt;%@ CodeTemplate Language=&quot;C#&quot; TargetLanguage=&quot;C#&quot; Description=&quot;Perf diag template.&quot; %&gt;
<br>&lt;%@ Property Name=&quot;ClassName&quot; Type=&quot;System.String&quot; Default=&quot;PerfCounterInfo&quot; Category=&quot;Options&quot; Description=&quot;ClassName.&quot; %&gt;
<br>&lt;%@ Import Namespace=&quot;System.Diagnostics&quot; %&gt;
<br>&lt;%@ Import Namespace=&quot;System.Text.RegularExpressions&quot; %&gt;
<br>
<br>using System;
<br>using System.Diagnostics;
<br>
<br>namespace <a title="MbUnit, Generating Unit Testing and Model Based Testing Framework for .NET Framework" href="http://mbunit.tigris.org" target="_blank">MbUnit</a>.Core.Framework
<br>{
<br> public class &lt;%= ClassName %&gt;
<br> {
<br> #region Constructors
<br> private &lt;%= ClassName %&gt;() {}
<br> #endregion
<br>
<br> #region Categories
<br>&lt;% foreach(PerformanceCounterCategory cat in PerformanceCounterCategory.GetCategories()){
<br>if (!this.categories.Contains(cat.CategoryName))
<br> continue;
<br>try
<br>{
<br>PerformanceCounter[] counters=null;
<br>bool hasInstance = cat.GetInstanceNames().Length!=0;
<br>if (!hasInstance)
<br> counters = cat.GetCounters();
<br>else
<br> counters = cat.GetCounters(cat.GetInstanceNames()[0]);
<br> foreach(PerformanceCounter counter in counters) {};
<br>%&gt;
<br> #region &lt;%= cat.CategoryName %&gt;
<br> /// &lt;summary&gt;
<br> /// &lt;%= cat.CategoryHelp %&gt;
<br> /// &lt;/summary&gt;
<br> public sealed class &lt;%= GetCategoryClassName(cat) %&gt;
<br> {
<br> public const string CategoryName = @&quot;&lt;%= cat.CategoryName %&gt;&quot;;
<br> #region Constructors
<br> private &lt;%= GetCategoryClassName(cat) %&gt;(){}
<br> #endregion
<br>
<br>&lt;%foreach(PerformanceCounter counter in counters) {%&gt;
<br> #region &lt;%= counter.CounterName %&gt;
<br> /// &lt;summary&gt;
<br> /// &lt;%= counter.CounterHelp %&gt;
<br> /// &lt;/summary&gt;
<br> public sealed class &lt;%= GetCounterClassName(counter)%&gt;
<br> {
<br> public const string CounterName = @&quot;&lt;%= counter.CounterName%&gt;&quot;;
<br> private &lt;%= GetCounterClassName(counter)%&gt;(){}
<br>&lt;% if (hasInstance){%&gt;
<br> /// &lt;summary&gt;
<br> /// Gets the value of the &lt;see cref=&quot;PerformanceCounter&quot;/&gt;.
<br> /// &lt;summary&gt;
<br> /// &lt;returns&gt;
<br> /// Value returned by &lt;see cref=&quot;PerformanceCounter.NextValue&quot;/&gt;
<br> /// for the current instance.
<br> /// &lt;/returns&gt;
<br> public static float NextValue()
<br> {
<br> return NextValue(Process.GetCurrentProcess().ProcessName);
<br> }
<br>
<br> public static float NextValue(string instanceName)
<br> {
<br> return PerfCounterAssert.NextValue(
<br> &lt;%= GetCategoryClassName(cat) %&gt;.CategoryName,
<br> CounterName,
<br> instanceName
<br> );
<br> }
<br>&lt;%}else{%&gt;
<br> /// &lt;summary&gt;
<br> /// Gets the value of the &lt;see cref=&quot;PerformanceCounter&quot;/&gt;.
<br> /// &lt;summary&gt;
<br> /// &lt;returns&gt;
<br> /// Value returned by &lt;see cref=&quot;PerformanceCounter.NextValue&quot;/&gt;.
<br> /// &lt;/returns&gt;
<br> public static float NextValue()
<br> {
<br> return PerfCounterAssert.NextValue(
<br> &lt;%= GetCategoryClassName(cat) %&gt;.CategoryName,
<br> CounterName,
<br> null
<br> );
<br> }
<br>&lt;%}%&gt;
<br> }
<br> #endregion
<br>&lt;%} // GetCounters %&gt;
<br> }
<br> #endregion
<br>&lt;%
<br>}catch(Exception)
<br>{}
<br>%&gt;
<br>
<br>
<br>&lt;%} // GetCategories %&gt;
<br> #endregion
<br>
<br> public static float NextValue(
<br> string categoryName,
<br> string counterName,
<br> string instanceName
<br> )
<br> {
<br> using (PerformanceCounter counter = new PerformanceCounter(
<br> categoryName,
<br> counterName,
<br> instanceName,
<br> true)
<br> )
<br> {
<br> return counter.NextValue();
<br> }
<br> }
<br> }
<br>}
<br>
<br>&lt;script runat=&quot;template&quot;&gt;
<br>private System.Collections.Specialized.StringCollection categories = null;
<br>
<br>[Category(&quot;Options&quot;)]
<br>public System.Collections.Specialized.StringCollection Categories
<br>{
<br> get
<br> {
<br> if (categories==null)
<br> {
<br> categories = new System.Collections.Specialized.StringCollection();
<br> foreach(PerformanceCounterCategory cat in PerformanceCounterCategory.GetCategories()){
<br> categories.Add(cat.CategoryName);
<br> }
<br> }
<br> return categories;
<br> }
<br> set
<br> {
<br> this.categories=value;
<br> }
<br>}
<br>
<br>public string Capitalize(string name)
<br>{
<br> return name[0] + name.Substring(1,name.Length-1);
<br>}
<br>public string Normalize(string name)
<br>{
<br> name = Regex.Replace(name,@&quot;[A-Z]+&quot;,new System.Text.RegularExpressions.MatchEvaluator(Capit));
<br> name = Regex.Replace(name,@&quot;#&quot;,@&quot;Nb&quot;);
<br> name = Regex.Replace(name,@&quot;\W&quot;,@&quot;&quot;);
<br>
<br> return name;
<br>}
<br>
<br>public string Capit(System.Text.RegularExpressions.Match m)
<br>{
<br> return m.Value[0] + m.Value.Substring(1,m.Value.Length-1).ToLower();
<br>}
<br>public string GetCategoryClassName(PerformanceCounterCategory cat)
<br>{
<br> string name = Normalize(cat.CategoryName);
<br>
<br> return String.Format(&quot;{0}&quot;,name);
<br>}
<br>public string GetCounterClassName(PerformanceCounter counter)
<br>{
<br> string name = Normalize(counter.CounterName);
<br>
<br> return String.Format(&quot;{0}&quot;,name);
<br>}
<br>&lt;/script&gt;
Jonathan de Halleux
Monday, June 06, 2005 5:41:44 PM UTC
Nice addition. Now we can replace the code we've written to check perf stats with WMI in unit tests. FYI: WMI validation might be another interesting attribute. It has some more stats than performance counters.
<br>FYI: Assert.AreEqual(&quot;Perfomance&quot;, &quot;Performance&quot;);// Check title :)
Scott Willeke
Monday, June 06, 2005 5:41:45 PM UTC
Hi Scott,
<br>
<br>Any links on WMI, tutorial ?
<br>
Jonathan de Halleux
Monday, June 06, 2005 5:41:45 PM UTC
Peli's Blog
Monday, June 06, 2005 5:41:45 PM UTC
Peli's Blog
Monday, June 06, 2005 5:41:46 PM UTC
I posted some comments to a friend of mine who has been working with me on the perf testing about using WMI for such things: <a target="_new" href="http://blogs.pingpoet.com/philblog/archive/2004/06/16/592.aspx#594">http://blogs.pingpoet.com/philblog/archive/2004/06/16/592.aspx#594</a>
Scott Willeke
Monday, June 06, 2005 5:41:46 PM UTC
Greetings from Malaga (Spain). Antonio :-)
Malaga
Comments are closed.