Saturday, October 6, 2012

Inline Methods

One of the cool features of C++ for super optimizations are inline functions, starting .NET 4.5 there's a way to ask the framework to prefer using them with MethodImplOptions.AggressiveInlining

In older versions of the framework, there was only a way to disable this optimization for a specific method using MethodImplOptions.NoInlining, otherwise the framework would attempt to inline certain methods.

The test results shows that for very small methods, most of the time is spent on method calling, which needs to push the parameters, return address, frames, exception handler, locally declared variables flags and registers, execute the method's code and pop everything back out, I've seen significant improvements on small methods which the framework deems unworthy so if you have many loops, calling many small functions and its worth the time saved, I would try adding this attribute.

The test in the demo project shows that it takes about 2/3 of the time spent on an small/redirection function and 10 times difference in medium functions, say you have millions of calls to these methods or you have them nested deeply one inside the other and your program is CPU intensive, you could shave a lot of time from it by using inlining.

Note that lambdas and delegates are not optimized, and how could they? they are assigned at runtime.

The only real reason I could find for using MethodImplOptions.NoInlining is for exception handling, either you need to know the exact line something failed and the one you're getting doesn't make any sense or you're using StackTrace and you need an exact stack, note that in debug mode methods are not optimized.

Perhaps another reason might be reflection, if your code is reflection intensive but you see differences in behavior between debug and release, you might want to try MethodImplOptions.NoInlining for these methods, if that doesn't help, try also NoOptimization, but understanding this behavior should be more important then trying to throw these attributes at methods randomly.

The way you would use these attributes is:


[MethodImpl(MethodImplOptions.AggressiveInlining)]
void method()
{
    //do something
}

[MethodImpl(MethodImplOptions.NoInlining)]
void method()
{
    //do something
}

[MethodImpl(MethodImplOptions.NoOptimization)]
void method()
{
    //do something
}


Here's the project I've used to test and validate these ideas, note that to see a significant change between the methods I've used about 5,000,000 iterations, in the simple methods I've used for testing there was about 10 times change between the inline methods to the non inlined methods.

https://github.com/drorgl/ForBlog/tree/master/InlineMethodTest

No comments:

Post a Comment