Comparing execution speed of .NET dynamic proxy frameworks

A recent comment on Twitter from Tim Barcz started me thinking about alternative proxy frameworks (alternative to Castle Dynamic Proxy that is). Recently LinFu Dynamic Proxy started gaining some popularity, after it was included as one of standard bytecode providers in NHibernate.

Disclaimer:

To make things clear. I’m a long time user of Castle Dynamic proxy and I may be biased towards it. I also happen to know how to use it, contrary to all the other frameworks, that’s why the following test may not be realizing their full potential. If you spot a non-optimal use of any of the frameworks in the following test, let me know and I’ll update it.

Having said that, I put together a small sample test project, where I generate a one-interceptor proxy for a simple interface with each framework and call a method on this proxy 100,000 times.

The interface is as simple as it can be:

public interface IMyInterface1
{
    string Method1(int i);
}

Each interceptor looks roughly the same, and it only sets a return value for the method:

internal class SpringInterceptor : AopAlliance.Intercept.IMethodInterceptor
{
    public object Invoke(AopAlliance.Intercept.IMethodInvocation invocation)
    {
        //Debug.WriteLine("Hey, I intercepted the call! - Spring");
        return 5.ToString();
    }
}

I tested four frameworks. Castle Dynamic Proxy 2.1 RC1, LinFu Dynamic Proxy 1.01, Spring.NET 1.2, which is a big framework in itself, but it has some pretty powerful proxying capabilities, and Microsoft Unity 1.2 which has now some proxying capabilities as well.

Here’s the result of the test on my 4 year old, 2GHz one-core PC:

proxy_frameworks_1

The first pass was a warm up, to let the jitter kick in, so the really important stuff, is the second pass.

Castle Dynamic Proxy was the fastest one, which is not really a surprise for me. It’s designed to be fast and lightweight, and also has some pretty powerful capabilities that allow you to customize the proxy type being created so that you don’t waste cycles intercepting methods you don’t want to intercept, or calling interceptors you don’t need called for a particular method. (for an in-depth overview of Castle Dynamic Proxy see my tutorial series).

The second one was Spring.NET which took over 3 times longer. This is however still pretty fast, and considering that it’s a pretty extensible and configurable framework as well, I’m sure in real life scenario you can squeeze very good performance out of it.

Third one, Unity was an order of magnitude slower than Castle. This is not a surprise considering how bloated and over engineered it is. To be fair however, this may as well be due to strong tie between Unity IoC container and proxy framework. The proxy framework does not seem to be operable outside of the container, so the performance hit, may be partially due to some container overhead.

LinFu was two orders of magnitude slower than Castle. This was really surprising. Or at least until I noticed that it gathers a call stack for each and every invocation, and as I mentioned, this can (as clearly visible) be a performance overkill. I looked for a way to turn it off, but it seems there isn’t any. Also the only way of calling the intercepted method is via MethodInfo.Invoke, which is also a lot slower than direct invocation (or invocation via a delegate).

Note that this is an isolated case of a single performance test. I thought it’s the most important one, but it’s just my opinion. I also didn’t talk about capabilities, which should be your major concern when selecting a framework. – Can it support my scenario is the ultimate test. Frankly, the fastest two, are also the most mature and powerful.

You can check the complete code here.

UPDATE:

Here’s a screenshot from a profiler showing the LinFu’s proxy call tree. As you can clearly see, the major performance hit (over 90% of the time!) is in StackTrace constructor. It also obtains a MethodInfo dynamically instead of caching it, like other frameworks do, which is an expensive operation as well.

LinFu

UPDATE 2:

LinFu has been updated and it no longer collects stack trace information: I re-ran the test and you can see the results here.

 

Comments

Tim Barcz says:

Krzysztof,

I am suprised to see LinFu’s performance degrade so badly….especially considering how LinFu was represented on Twitter.

Any theories on why such a slow performance for LinFu? Age? Implementation?

Interesting, I had this task on my TODO list to see if we could improve Castle DynamicProxy for common cases, because I was hearing so many stories of people saying how lightweight and fast LinFu is. In this case it is definitely not.

@Jono

By Lightweight, people may mean it’s small. It has really small API with no explicit differentiation between kinds of proxies (interface proxy, class proxy, interface proxy without target etc). It also lets you have only one interceptor per proxy, it does not provide hooks to decide what to intercept and what not.
It may be sufficient for trivial cases, but I simply view it as an one-man v1.0 product. It has made its goal of being small, but at a cost of features and runtime speed.

LinFu DP sounds more basic than I thought it was going to be, but as you said it was probably designed to be small not feature packed.

Philip Laureano says:

Hmm. I think the reason why you might have gotten some really slow results is because calling MethodInfo.Invoke is several orders of magnitude slower than doing a native delegate call. If you call MethodInfo.Invoke(), there really is no contest here.

If you did a DynamicMethod call on the method, however, I think you might just get more accurate results…

@Philip

I’m not calling MethodInfo.Invoke, take a look at the code.
Your article on CodeProject, shows that it’s the way to go to invoke intercepted method, and I only noted that it’s slower than what other frameworks do.

// Note: If you wanted to call the original
// implementation, uncomment the following line:
//result = info.TargetMethod.Invoke(_target, info.Arguments);

That’s the piece of your article. If there’s a better way of handling method invocation now, please let me know 🙂
But again, this was not a factor in my test.

Philip Laureano says:

Hi Krzysztof,

Thanks for pointing the stack trace out–that was the last place I would have looked! Anyway, I went ahead and patched LinFu.DynamicProxy so that the stack trace has been removed. 🙂 Take a look at v1.02, and let me know if there’s a change in performance.

Thanks for the feedback!

Regards,

Philip Laureano

this is great information that i know a lot of people are interested in.
thanks for the great offer, this really nice idea.

Ronald Widha says:

Didn’t know unity comes with a dynamic proxy ability. Let me check that out.
Thanks!

@Ronald,

Yes, it does, although I found it… not very friendly to use, but that’s my impression of Unity in general.