Calling Code Dynamically

On February 5, 2004 Eric Gunnerson, Program Manager on the Visual C#, published an article on msdn where he explores the performance aspects of various methods of calling code dynamically.

Results:

Because the method called does a trivial amount of work, it will accentuate the differences that you see between different methods. The more work the method does, the less difference there will be between the different methods of calling, and therefore big differences here may be inconsequential in actual code.

Figure 1 is a pretty picture of the results for Visual Studio 7.1, when calling a method 100,000 times:

Figure 1. Screenshot of results

It isn't surprising that the direct call is the fastest. The call that is being made can be easily put inline by the JIT, which means that there is no call overhead. Interfaces suffer compared to direct calls because they can't be put inline (and this is true of virtual calls as well). Delegates are a bit slower than interfaces.

InvokeMember() is very slow, with interface calls being some 200 times faster than InvokeMember() calls. InvokeMember() does a tremendous amount of work to make sure it is called safely and that it is calling the right method, and this shows. Similarly for the custom delegate case, calling DynamicInvoke() does a lot of work to make sure the call is okay.

The CustomClass version works okay, but it suffers from a lot of overhead in creating the custom class in the first place, which means it's only about 5 percent as fast as a direct call for 100,000 calls. As the number of calls goes up, the overhead will matter less, and it will be roughly the speed of the interface call.

What About Whidbey ?

In Whidbey, the results are much the same, with the exception of the delegate case, which has been optimized, and now provides similar performance to interfaces. So, if you were unhappy with the performance of delegates, you should be happier with what you get in Whidbey.

 

1 Comment

  • DOH! This is a really bad demonstration of the speed of method calls. Running on v1.1.4322.573 the following code:



    int sum = 0;

    for(int i = 0 ;i<100000; i++)

    {

    sum += p.Process(1);

    }



    Generates the following assembly:



    06ce006b xor edx,edx

    06ce006d xor ecx,ecx

    06ce006f mov eax,[esi]

    06ce0071 mov eax,0x2

    06ce0076 add eax,edx

    06ce0078 mov edx,eax

    06ce007a inc ecx

    06ce007b cmp ecx,0x186a0

    06ce0081 jl 06ce0071



    After slapping a NoInlining attribute on the call I get this:



    06ce006d xor ebx,ebx

    06ce006f xor edi,edi

    06ce0071 mov ecx,esi

    06ce0073 mov edx,0x1

    06ce0078 cmp [ecx],ecx

    06ce007a call dword ptr [003f5454]

    06ce0080 add ebx,eax

    06ce0082 inc edi

    06ce0083 cmp edi,0x186a0

    06ce0089 jl 06ce0071



    I downloaded the MSI thinking maybe the article just left this part out, but unfortunately that wasn’t the case. Of course it’s not surprising the direct call is so much faster: the call doesn’t happen! Mmmm… Inlining.



    There are some nice details that have been gotten right here though: Without the store to theSum at the end the add instruction would have been optimized away too!

Comments have been disabled for this content.