甚至无法获得内联的简单方法(?)

Aci*_*dic 3 c# inline .net-4.0 visual-studio-2010

从逻辑上讲,我总是假设C#编译器会使用非常简短的方法,因此只需手动输入方法中的代码就不会显示任何开销......

直到今天 - 当我尝试对各种方法进行基准测试并手动内联代码时.事实证明,对于我来说,即使最简单的代码也会显示与手动内联对应项相比的方法调用开销.
实际上,我找不到任何内联方法的线索- 所以我进行了一个简单的测试.

使用的系统:

  • 英特尔C2D E7200(双核)2.53GHz
  • 4GB DDR2
  • Windows 7 64位
  • .NET 4.0
  • Visual Studio 2010 Ultimate

所有测试均在没有Debug和使用Release Configuration(Optimize Code)的情况下执行.

这是我用来进行基准测试的代码:

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);
}
Run Code Online (Sandbox Code Playgroud)

[1]首先,我简单地对一个简单的增量命令进行基准测试:

// in Main
for (int i = 0; i < iterations; i++)
{
    s = s + 1;
}
Run Code Online (Sandbox Code Playgroud)

5次运行的结果:

  1. 867ms
  2. 877ms
  3. 868ms
  4. 865ms
  5. 870ms

[2]切换到方法调用:

static int Increment(int a)
{
    return a + 1;
}
Run Code Online (Sandbox Code Playgroud)

...

// in Main
for (int i = 0; i < iterations; i++)
{
    s = Increment(s);
}
Run Code Online (Sandbox Code Playgroud)

5次运行的结果:

  1. 2161ms
  2. 2159ms
  3. 2194ms
  4. 2177ms
  5. 2163ms

哎哟! 显然这个方法有一个开销.

我试过使用反射,并MethodBase.GetCurrentMethod().NameIncrement方法中打印出来; 它确实是打印Increment- 意味着该方法没有内联.

接下来我尝试将该[MethodImpl(MethodImplOptions.NoInlining)]属性添加到方法中 - 但基准时间保持完全相同.

在调试模式下,优化代码设置为false,第一个测试稍慢,而第二个测试慢两倍; 而NoInlining属性又不会影响性能.


我在这里做错了什么,即使这样一个简单的方法没有开销也无法工作?为什么会这样?
当然这不是预期的行为 - 或者是它?

注意:Java中的类似测试显示此类方法调用没有开销.(使用Eclipse + JDK 1.7,Java也似乎有很多在这个快.)

Mic*_*Liu 10

如果从Visual Studio中运行程序,请确保使用Start Without Debugging命令; 否则,可能会禁用内联等一些优化.

如果我首先使用Start Without Debugging命令运行程序,然后附加调试器并查看for循环的x86反汇编,无论循环s直接递增还是调用,我都会得到相同的结果Increment; 也就是说,方法调用是内联的:

00000049  xor         eax,eax
0000004b  inc         ebx
0000004c  inc         eax
0000004d  cmp         eax,0EE6B280h
00000052  jl          0000004B
Run Code Online (Sandbox Code Playgroud)

相反,如果我使用Start Debugging命令来运行程序,则不会内联方法调用:

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
Run Code Online (Sandbox Code Playgroud)