Logically, I always assumed that very short and simple methods would get inlined by the C# Compiler and thus won't show any overhead compared to simply typing the code in the methods by hand...
Until today - when I tried to benchmark various methods and manually inlined code. Turns out that (for me) even the most simple code will show a method call overhead compared to its manually inlined counterpart.
Actually, I could find no clues as to any method being inlined - So I ran a simple test.
System used:
All tests were performed without Debug and using Release Configuration (Optimize Code).
Here's the code I used to benchmark:
static void Main()
{
const int iterations = 250000000; // 250 million iterations
Thread.Sleep(1000); // sleep for one second
var sw = new Stopwatch();
int s = 0;
sw.Start();
for (int i = 0; i < iterations; i++)
{
// incrementing s by 1 in various ways
}
sw.Stop();
Console.WriteLine("Time: {0}ms", sw.ElapsedMilliseconds);
}
[1] First, I've simply benchmarked a simple increment command:
// in Main
for (int i = 0; i < iterations; i++)
{
s = s + 1;
}
Results from 5 runs:
[2] Switching to a method call:
static int Increment(int a)
{
return a + 1;
}
...
// in Main
for (int i = 0; i < iterations; i++)
{
s = Increment(s);
}
Results from 5 runs:
Ouch! Obviously there's an overhead for the method.
I've tried to use reflection, and printed MethodBase.GetCurrentMethod().Name from within the Increment method; it was indeed printing Increment - meaning the method isn't inlined.
Next I've tried to add the [MethodImpl(MethodImplOptions.NoInlining)] attribute to the method - but the benchmark time stayed exactly the same.
In Debug mode and with Optimize Code set to false, the first test is slightly slower while the second one is about two times slower; and yet again the NoInlining attribute doesn't impact performance.
Am I doing something wrong here that I fail to make even such a simple method work without an overhead? Why is this happening?
Surely this can't be expected behavior - or is it?
Note: Similar testing in Java shows no overhead to such a method call. (using Eclipse + JDK 1.7, Java also seems to be A LOT faster at this.)
If you're running the program from within Visual Studio, make sure you use the Start Without Debugging command; otherwise, some optimizations like inlining may be disabled.
If I first use the Start Without Debugging command to run the program, then attach the debugger and look at the x86 disassembly of the for loop, I get the same thing whether the loop increments s directly or calls Increment; that is, the method call is inlined:
00000049 xor eax,eax
0000004b inc ebx
0000004c inc eax
0000004d cmp eax,0EE6B280h
00000052 jl 0000004B
In contrast, if I use the Start Debugging command to run the program, then the method call is not inlined:
00000060 xor edx,edx
00000062 mov dword ptr [ebp-0Ch],edx
00000065 nop
00000066 jmp 0000007D
00000068 mov ecx,dword ptr [ebp-8]
0000006b call dword ptr ds:[00801F50h]
00000071 mov dword ptr [ebp-10h],eax
00000074 mov eax,dword ptr [ebp-10h]
00000077 mov dword ptr [ebp-8],eax
0000007a inc dword ptr [ebp-0Ch]
0000007d cmp dword ptr [ebp-0Ch],0EE6B280h
00000084 jl 00000068
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With