I posted this question earlier about dynamically compiling code in C#, and the answer has lead to another question.
One suggestion is that I use delegates, which I tried and they work well. However, they are benching at about 8.4 X slower than direct calls, which makes no sense.
What is wrong with this code?
My results, .Net 4.0, 64 bit, ran exe directly: 62, 514, 530
public static int Execute(int i) { return i * 2; }
private void button30_Click(object sender, EventArgs e)
{
CSharpCodeProvider foo = new CSharpCodeProvider();
var res = foo.CompileAssemblyFromSource(
new System.CodeDom.Compiler.CompilerParameters()
{
GenerateInMemory = true,
CompilerOptions = @"/optimize",
},
@"public class FooClass { public static int Execute(int i) { return i * 2; }}"
);
var type = res.CompiledAssembly.GetType("FooClass");
var obj = Activator.CreateInstance(type);
var method = type.GetMethod("Execute");
int i = 0, t1 = Environment.TickCount, t2;
//var input = new object[] { 2 };
//for (int j = 0; j < 10000000; j++)
//{
// input[0] = j;
// var output = method.Invoke(obj, input);
// i = (int)output;
//}
//t2 = Environment.TickCount;
//MessageBox.Show((t2 - t1).ToString() + Environment.NewLine + i.ToString());
t1 = Environment.TickCount;
for (int j = 0; j < 100000000; j++)
{
i = Execute(j);
}
t2 = Environment.TickCount;
MessageBox.Show("Native: " + (t2 - t1).ToString() + Environment.NewLine + i.ToString());
var func = (Func<int, int>) Delegate.CreateDelegate(typeof (Func<int, int>), method);
t1 = Environment.TickCount;
for (int j = 0; j < 100000000; j++)
{
i = func(j);
}
t2 = Environment.TickCount;
MessageBox.Show("Dynamic delegate: " + (t2 - t1).ToString() + Environment.NewLine + i.ToString());
Func<int, int> funcL = Execute;
t1 = Environment.TickCount;
for (int j = 0; j < 100000000; j++)
{
i = funcL(j);
}
t2 = Environment.TickCount;
MessageBox.Show("Delegate: " + (t2 - t1).ToString() + Environment.NewLine + i.ToString());
}
As Hans mentions in the comments on your question, the
Execute
method is so simple that it's almost certainly being inlined by the jitter in your "native" test.So what you're seeing isn't a comparison between a standard method call and a delegate invocation, but a comparison between an inlined
i * 2
operation and a delegate invocation. (And thati * 2
operation probably boils down to just a single machine instruction, about as fast as you can get.)Make your
Execute
methods a bit more complicated to prevent inlining (and/or do it with theMethodImplOptions.NoInlining
compiler hint); then you'll get a more realistic comparison between standard method calls and delegate invocations. Chances are that the difference will be negligible in most situations:It makes sense. Delegates are not function pointers. They imply type checking, security and a lot of other stuffs. They're more close to the speed of a virtual function call (see this post) even if the performance impact derives from something completely different.
For a good comparison of different invocation techniques (some of them not mentioned in the question) read this article.