Saturday, May 1, 2010

Genetic Programming: C# Reflection Performance and Improvements with Delegate

I think this is going to be the final installment in the Reflection Performance "Trilogy". I found several blogs, articles and discussions that show ways to get better performance from reflection by utilizing delegates. Hooking up a delegate using reflection provides a very noticeable increase in performance.

Here are the results:


Here are the resources I used:
Jon Skeet's article is pretty good: http://msmvps.com/blogs/jon_skeet/archive/2008/08/09/making-reflection-fly-and-exploring-delegates.aspx
Joel Pobar's article on reflection: http://msdn.microsoft.com/en-us/magazine/cc163759.aspx

Here is the code:

class Program
{
static Dictionary <int, List <Delegate>> _delegate =
new Dictionary <int, List <Delegate>>();

static Stopwatch _stopwatch = new Stopwatch();

static void Main(string[] args)
{
Console.WriteLine("Frequency = " + Stopwatch.Frequency);
DyanmicInvocationTest();
Console.WriteLine("Press any key to exit!");
Console.ReadKey();
}

static void DyanmicInvocationTest()
{
Functions fn = new Functions();
Type typeFn = fn.GetType();
MethodInfo[] methods = typeFn.GetMethods();
foreach (MethodInfo method in methods)
{
if (method.Name.StartsWith("GP"))
{
ParameterInfo[] pi = method.GetParameters();

if (!_delegate.ContainsKey(pi.Length))
{
_delegate.Add(pi.Length, new List());
}

switch(pi.Length)
{
case 0:
_delegate[pi.Length].Add(
Delegate.CreateDelegate(
typeof(Functions.ZeroParam), fn, method));
break;
case 1:
_delegate[pi.Length].Add(
Delegate.CreateDelegate(
typeof(Functions.OneParam), fn, method));
break;
default:
break;
}
}
}
int numRuns = 100 * 1000;
long time = 0;

// Delegate
Console.WriteLine("*** Running dynamic delegate test ***");
for (int i = 0; i < numRuns; ++i)
{
time += DynamicInvokeDelegate(fn);
_stopwatch.Reset();
}

Console.WriteLine("Avg dynamic delegate invoke = " + (double)time / (double)numRuns);
time = 0;

Console.WriteLine("Average time normal = " + (double)time / (double)numRuns);
}

static Int64 DynamicInvokeDelegate(Functions fn)
{
Type typeFn = fn.GetType();
object[] zeroParam = new object[0];
object[] oneParam = new object[1] { 1.0 };

_stopwatch.Start();
foreach (int key in _delegate.Keys)
{
//Console.WriteLine(
// String.Format("num param {0}, num fn {1}",
// key, _functions[key].Count));
foreach (Delegate method in _delegate[key])
{
switch (key)
{
case 0:
method.DynamicInvoke(zeroParam);
break;
case 1:
method.DynamicInvoke(oneParam);
break;
default:
break;
}
}
}

_stopwatch.Stop();
return _stopwatch.ElapsedTicks;
}
}

No comments:

Post a Comment