Sunday, August 01, 2004 6:11 PM
pgolde
A performance mystery
I was doing some rough performance comparisons of different calling mechanisms in Beta 1, to see what was fast and what wasn't. I tried looking at interface calls vs. delegate calls, both using generic and not using generic. The results were almost entirely satisfying: an interface call and a delegate call were just about the same speed, and using generics did not slow thing down.
However, there was one very notable exception: if a delegate is created that refers to a method with type parameters on the method itself, calls through the delegate were about 80 times slower than other delegate or interface calls. Here's an example:
class Q<T> where T : IComparable<T>
{
public int Compare(T x, T y)
{
return x.CompareTo(y);
}
}
class R
{
public int Compare<T>(T x, T y) where T : IComparable<T>
{
return x.CompareTo(y);
}
}
Both classes have a Compare method that takes two objects of type T, and returns an I. In class Q, the type parameter is on the class Q itself, while in class R, the type parameter is on the method Compare. When the methods are directly called:
Q<int> q = new Q<int>();
R r = new R();
q.Compare(4,5);
r.Compare<int>(4,5); // runs just as fast as the previous call
the two methods execute equally fast, as you would expect. But if a delegate is created onto each methods, and the delegate is then called:
Comparer<int> d1 = q.Compare;
Comparer<int> d2 = r.Compare<int>;
d1(4,5);
d2(4,5); // runs much slower than the previous call
then the call through delegate d2 is much much slower (about a factor of 80) than the call through delegate d1.
Very strange indeed! Off the type of my head, I can't think of any reason why this should be the case. Unfortunately, I used this exact construct in some of the Power Collections code, when doing comparisons of elements. To get decent performance, I'll have to recode it to use interface calls instead of delegates. Although slightly more cumbersome to write, it will probably be better code anyway.