F
Fernando Cacciola
Hi,
I was initially benchmarking inlinine capabilities of C# in VS 2005 while I
stumble on the following surprising results.
Please take a look at the following complete sample (you can just copy+paste
and compile it yourself)
using System;
public interface I { void Do () ; }
public class A : I { public void Do () {} }
public struct B<T> : I { public void Do () {} }
public class C : I { public virtual void Do () {} }
public class Test
{
const int c = int.MaxValue / 10 ;
static public void Try( I f )
{
int s = Environment.TickCount ;
for( int i = 0 ; i < c ; ++ i )
f.Do();
int e = Environment.TickCount ;
Console.WriteLine(e-s);
}
static public void GTry<F>( F f ) where F : I
{
int s = Environment.TickCount ;
for( int i = 0 ; i < c ; ++ i )
f.Do();
int e = Environment.TickCount ;
Console.WriteLine(e-s);
}
}
class Program
{
static void Main(string[] args)
{
Test.Try ( new A() );
Test.GTry( new A() );
Test.Try ( new B<int>() );
Test.GTry( new B<int>() );
Test.Try ( new C() );
}
}
<<<<<<<<<<<
In that program there are 3 types:
A a non-generic interface
A non-generic class implementing the interface.
And a generic class also implementing the interface.
All the interface declares is a trival no-op method.
There are two _exactly equivalent_ methods which differ ONLY in that one
takes the interface non-generically, and the other takes any type
implementing the interface generically.
The methods just call the trivial function on the parameter a number of
times and outputs the ellapsed time taken.
Do you expect any difference in the times taken to call Do() in each case?
I certianly wouldn't (Do is not a virtual method and it's trivial)
Now compile in release mode (making sure the code is optimized) and run it
_outside the IDE_.
I get the following surprising results:
1515
1516
2531
140
2109
Why is this surprising?
A few things:
(1) The method from the non-generic class A is not inlined at all in the
calls.
(2) The method in the generic-class B is as slow as if it were virtual
(compare it to class C) when called from the non-generic interface
(something which doesn't happen with A)
(3) The method is ONLY fully inlined when called on the generic-class B (not
on the non-generic class A) AND from the a generic parameter (thus fully
retaining its dynamic type) rather than an interface.
Can anyone help me make sense out of it? [or spot a mistake in the
benchmarks?]
TIA
I was initially benchmarking inlinine capabilities of C# in VS 2005 while I
stumble on the following surprising results.
Please take a look at the following complete sample (you can just copy+paste
and compile it yourself)
using System;
public interface I { void Do () ; }
public class A : I { public void Do () {} }
public struct B<T> : I { public void Do () {} }
public class C : I { public virtual void Do () {} }
public class Test
{
const int c = int.MaxValue / 10 ;
static public void Try( I f )
{
int s = Environment.TickCount ;
for( int i = 0 ; i < c ; ++ i )
f.Do();
int e = Environment.TickCount ;
Console.WriteLine(e-s);
}
static public void GTry<F>( F f ) where F : I
{
int s = Environment.TickCount ;
for( int i = 0 ; i < c ; ++ i )
f.Do();
int e = Environment.TickCount ;
Console.WriteLine(e-s);
}
}
class Program
{
static void Main(string[] args)
{
Test.Try ( new A() );
Test.GTry( new A() );
Test.Try ( new B<int>() );
Test.GTry( new B<int>() );
Test.Try ( new C() );
}
}
<<<<<<<<<<<
In that program there are 3 types:
A a non-generic interface
A non-generic class implementing the interface.
And a generic class also implementing the interface.
All the interface declares is a trival no-op method.
There are two _exactly equivalent_ methods which differ ONLY in that one
takes the interface non-generically, and the other takes any type
implementing the interface generically.
The methods just call the trivial function on the parameter a number of
times and outputs the ellapsed time taken.
Do you expect any difference in the times taken to call Do() in each case?
I certianly wouldn't (Do is not a virtual method and it's trivial)
Now compile in release mode (making sure the code is optimized) and run it
_outside the IDE_.
I get the following surprising results:
1515
1516
2531
140
2109
Why is this surprising?
A few things:
(1) The method from the non-generic class A is not inlined at all in the
calls.
(2) The method in the generic-class B is as slow as if it were virtual
(compare it to class C) when called from the non-generic interface
(something which doesn't happen with A)
(3) The method is ONLY fully inlined when called on the generic-class B (not
on the non-generic class A) AND from the a generic parameter (thus fully
retaining its dynamic type) rather than an interface.
Can anyone help me make sense out of it? [or spot a mistake in the
benchmarks?]
TIA