3

論理的には、非常に短くて単純なメソッドは C# コンパイラによってインライン化されるため、単純にメソッドにコードを手動で入力する場合と比較してオーバーヘッドが発生しないと常に想定していました...

今日まで-さまざまなメソッドと手動でインライン化されたコードのベンチマークを試みたとき。(私にとって) 最も単純なコードでさえ、手動でインライン化されたものと比較してメソッド呼び出しのオーバーヘッドが発生することがわかりました。実際、インライン化されている
メソッドについて の手がかりを見つけることができなかったので、簡単なテストを実行しました。

使用したシステム:

  • インテル C2D E7200 (デュアルコア) 2.53GHz
  • 4GB DDR2
  • ウィンドウズ7 64ビット
  • .NET 4.0
  • Visual Studio 2010 アルティメット

すべてのテストは、デバッグなしでリリース構成 (コードの最適化)を使用して実行されました。

ベンチマークに使用したコードは次のとおりです。

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]まず、単純なインクリメント コマンドのベンチマークを行いました。

// in Main
for (int i = 0; i < iterations; i++)
{
    s = s + 1;
}

5 回実行した結果:

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

[2]メソッド呼び出しへの切り替え:

static int Increment(int a)
{
    return a + 1;
}

...

// in Main
for (int i = 0; i < iterations; i++)
{
    s = Increment(s);
}

5 回実行した結果:

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

痛い!明らかに、メソッドのオーバーヘッドがあります。

リフレクションを使用して、メソッドMethodBase.GetCurrentMethod().Name内から出力しようとしました。Incrementそれは確かに印刷されていましたIncrement-つまり、メソッドはインライン化されていません。

[MethodImpl(MethodImplOptions.NoInlining)]次に、属性をメソッドに追加しようとしましたが、ベンチマーク時間はまったく同じままでした。

Debug モードで Optimize Code を false に設定すると、最初のテストはわずかに遅くなり、2 番目のテストは約 2 倍遅くなります。また、NoInlining属性はパフォーマンスに影響しません。


ここで何か間違ったことをしているのですか?そのような単純なメソッドでさえオーバーヘッドなしで機能させることができませんか? なぜこうなった?
確かにこれは予想される動作ではありません - それともそうですか?

注: Java での同様のテストでは、このようなメソッド呼び出しに対するオーバーヘッドは示されていません。(Eclipse + JDK 1.7 を使用すると、Java もこれでかなり高速になるようです。)

4

1 に答える 1

10

Visual Studio 内からプログラムを実行している場合は、必ず[デバッグなしで開始]コマンドを使用してください。そうしないと、インライン化などの一部の最適化が無効になる場合があります。

最初に[デバッグなしで開始]コマンドを使用してプログラムを実行し、次にデバッガーをアタッチしてループの x86 逆アセンブリをfor確認すると、ループがs直接インクリメントするか呼び出しを行うかにかかわらず、同じことが得られますIncrement。つまり、メソッド呼び出しはインライン化されます。

00000049  xor         eax,eax
0000004b  inc         ebx
0000004c  inc         eax
0000004d  cmp         eax,0EE6B280h
00000052  jl          0000004B

対照的に、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
于 2012-06-21T03:45:11.740 に答える