|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThis article present NPerf a flexible performance benchmark framework. The framework provides custom attributes that the user uses the tag benchmark classes and methods. If you are familiar with NUnit [1], this is similar to the custom attributes they provide. The framework uses reflection to gather the benchmark testers, the tested types, runs the tests and output the results. The user just have to write the benchmark methods. At the end of the article, I illustrate NPerf with some metaphysic .NET question: interface vs. delegates, string concatenation race, fastest dictionary. QuickStart: Benchmarking IDictionaryLet's start with a small introductory example: benchmarking the All the custom attributes are located in the PerfTester attribute: defining testersFirst, you need to create a tester class that will contains method to do the benchmark. This tester method has to be decorated with the using NPerf.Framework;
[PerfTester(typeof(IDictionary),10)]
public class DictionaryTester
{
...
}
The
PerfTest attribute: adding benchmark testsThe [PerfTester(typeof(IDictionary),10)]
public class DictionaryTester
{
// explained below
private int count;
private Random rnd = new Random();
[PerfTest]
public void ItemAssign(IDictionary dic)
{
for(int i=0;i<this.count;++i)
dic[rnd.Next()]=null;
}
}
PerfSetUp and PerfTearDown AttributesOften, you will need to set up you tester and tested class before actually starting the benchmark test. In our example, we want to update the number of insertion depending the test repetition number. The [PerfTester(typeof(IDictionary),10)]
public class DictionaryTester
{
private int count;
private Random rnd = new Random();
[PerfSetUp]
public void SetUp(int index, IDictionary dic)
{
this.count = index * 1000;
}
}
The set-up method must return
If you need to clean up resources after the tests are run, you can use the [PerfTester(typeof(IDictionary),10)]
public class DictionaryTester
{
...
[PerfTearDown]
public void TearDown(IDictionary dic)
{
...
}
}
PerfRunDescriptor attribute: giving some information to the frameworkIn our example, we test the The [PerfTester(typeof(IDictionary),10)]
public class DictionaryTester
{
[PerfRunDescriptor]
public double Count(int index)
{
return index*1000;
}
}
Full example source.The full source of the example is as follows: using System;
using System.Collections;
using NPerf.Framework;
[PerfTester(typeof(IDictionary),10)]
public class DictionaryTester
{
private int count = 0;
private Random rnd = new Random();
[PerfRunDescriptor]
public double Count(int index)
{
return index*1000;
}
[PerfSetUp]
public void SetUp(int index, IDictionary dic)
{
this.count = (int)Math.Floor(Count(index));
}
[PerfTest]
public void ItemAssign(IDictionary dic)
{
for(int i =0;i<this.count;++i)
dic[rnd.Next()]=null;
}
}
Compiling and RunningCompile this class to an assembly and copy the NPerf binaries in the output folder: (NPerf.Cons.exe, NPerf.Core.dll, NPerf.Framework.Dll, NPerf.Report.Dll, ScPl.dll). NPerf.Cons.exe is a console application that dynamically loads the tester assemblies (that you need to specify), the assemblies that contains the tested types (you need to specify), runs the test and output charts using ScPl [2] (ScPl is a chart library under GPL). The call to NPerf.Cons.exe looks like this: NPerf.Cons -ta=MyPerf.dll -tdfap=System -tdfap=mscorlib
where
There are a number of other options that you can get by typing NPerf.Cons -h. Running the command line above will produce the following chart:
In the graph, you can see that some type failed the tests ( NPerf.Cons -ta=MyPerf.dll -tdfap=System -tdfap=mscorlib
-it=PropertyDescriptorCollection
Saving to XMLYou can also output the results to XML by adding the A few remarks
Overview of the CoreThe Getting the machine propertiesGetting the physical properties of the machine was a surprisingly difficult task. It took me a bunch of Google tries to get on the right pages. Anyway, here's the self-explaining code that get the machine properties: ManagementObjectSearcher query = new
ManagementObjectSearcher("SELECT * From Win32_ComputerSystem");
foreach(ManagementObject obj in query.Get())
{
long ram = long.Parse(obj["TotalPhysicalMemory"].ToString());
break;
}
query = new ManagementObjectSearcher("SELECT * From Win32_Processor");
foreach(ManagementObject obj in query.Get())
{
string cpu =(string)obj["Name"];
long cpuFrequency =
long.Parse(obj["CurrentClockSpeed"].ToString());
break;
}
TypeHelper, easier CustomAttribute supportA type helper static class was added to automate tedious tasks like check for custom attribute, get a custom attribute, etc... The public sealed class TypeHelper
{
public static bool HasCustomAttribute(
Type t,
Type customAttributeType);
public static bool HasCustomAttribute(
MethodInfo t,
Type customAttributeType)
public static Object GetFirstCustomAttribute(
Type t,
Type customAttributeType)
public static Object GetFirstCustomAttribute(
MethodInfo mi,
Type customAttributeType)
public static MethodInfo GetAttributedMethod(
Type t,
Type customAttributeType)
public static AttributedMethodCollection GetAttributedMethods(
Type t,
Type customAttributeType);
public static void CheckSignature(
MethodInfo mi,
Type returnType,
params Type[] argumentTypes);
public static void CheckArguments(
MethodInfo mi,
params Type[] argumentTypes);
}
Benchmark BonusIn order to illustrate the framework, I have written a few benchmark testers for classic performance questions about .NET. All these benchmarks are provided in the System.Perf project. IDictionary benchmark
String concatenation benchmark
Interface vs. Delegate
History
References
|
||||||||||||||||||||||