2009-06-29 11 views
16

パフォーマンス重視のアプリケーションを.Netに移行すると、C#のバージョンがプロセッサに応じてWin32/Cより30%から100%遅くなることがわかります(モバイルT7200プロセッサではそれ以上の違いがあります)。私はこれを示す非常に簡単なコードサンプルを持っています。簡潔にするために私はCのバージョンを示さなければならない - C#が直接翻訳したものです:C#(かなり遅い)とWin32/Cのパフォーマンスの違いはなぜですか?

#include "stdafx.h" 
#include "Windows.h" 

int array1[100000]; 
int array2[100000]; 

int Test(); 

int main(int argc, char* argv[]) 
{ 
    int res = Test(); 

    return 0; 
} 

int Test() 
{ 
    int calc,i,k; 
    calc = 0; 

    for (i = 0; i < 50000; i++) array1[i] = i + 2; 

    for (i = 0; i < 50000; i++) array2[i] = 2 * i - 2; 

    for (i = 0; i < 50000; i++) 
    { 
     for (k = 0; k < 50000; k++) 
     { 
      if (array1[i] == array2[k]) calc = calc - array2[i] + array1[k]; 
      else calc = calc + array1[i] - array2[k]; 
     } 
    } 
    return calc; 
} 

我々は我々が持っている「他」のためのWin32に解体を見れば:

35:    else calc = calc + array1[i] - array2[k]; 
004011A0 jmp   Test+0FCh (004011bc) 
004011A2 mov   eax,dword ptr [ebp-8] 
004011A5 mov   ecx,dword ptr [ebp-4] 
004011A8 add   ecx,dword ptr [eax*4+48DA70h] 
004011AF mov   edx,dword ptr [ebp-0Ch] 
004011B2 sub   ecx,dword ptr [edx*4+42BFF0h] 
004011B9 mov   dword ptr [ebp-4],ecx 

(これはデバッグではなく私と一緒にクマ)

最適化されたexeファイルのCLRデバッガを使用して最適化されたC#バージョンのための解体:

    else calc = calc + pev_tmp[i] - gat_tmp[k]; 
000000a7 mov   eax,dword ptr [ebp-4] 
000000aa mov   edx,dword ptr [ebp-8] 
000000ad mov   ecx,dword ptr [ebp-10h] 
000000b0 mov   ecx,dword ptr [ecx] 
000000b2 cmp   edx,dword ptr [ecx+4] 
000000b5 jb   000000BC 
000000b7 call  792BC16C 
000000bc add   eax,dword ptr [ecx+edx*4+8] 
000000c0 mov   edx,dword ptr [ebp-0Ch] 
000000c3 mov   ecx,dword ptr [ebp-14h] 
000000c6 mov   ecx,dword ptr [ecx] 
000000c8 cmp   edx,dword ptr [ecx+4] 
000000cb jb   000000D2 
000000cd call  792BC16C 
000000d2 sub   eax,dword ptr [ecx+edx*4+8] 
000000d6 mov   dword ptr [ebp-4],eax 

多くの命令、おそらくパフォーマンスの違いの原因。

だから、3つの質問は本当に:

  1. は、私は2つのプログラムのための正しい解体で探していますかのツールは私を誤解していますか?

  2. 生成される命令の数の違いが違いの原因でない場合は、何ですか?

  3. 私たちのパフォーマンス重視のコードをすべてネイティブDLLに保存する以外に、できることは何でしょうか。事前 で

おかげでスティーブ

私は「建物の性能の重要なネイティブアプリケーションのようなものうーん...

+0

アセンブリの指示の間にすべての改行を削除できますか? –

+0

いつもと同じように、それをプロファイルして、最もパフォーマンスが高いヒットコストを正確に把握してください。 (あなたのコードに時間がかかるのは分かりませんので、私たちに質問する必要はありません。プロファイラーに尋ねてください)それ以外の単純なトリックは、NGenを通してC#コードを実行することです。パフォーマンスがかなり向上するはずです。 – jalf

+0

比較するCLRのバージョン。私の知る限り、.NET 3.5 SP1 JITコンパイラは古いものよりも効率的です。また、x64 JITオプティマイザはx86よりも積極的です。 –

答えて

13

私は信じていると題した共同MS/Intelのセミナーに最近招待受けたPS配列の境界チェックの結果が表示されます。安全でないコードを使用すると、境界チェックを回避できます。

私はJITerがarray.Lengthまで上がっているループのようなパターンを認識し、境界チェックを回避できると信じていますが、あなたのコードがそれを利用できるようには見えません。

+9

私はこれらのりんご - オレンジをたくさん見ます "同一コード "は、おもちゃのコードとの比較を試みます。しかし、同等の品質の完全な製品品質のコードとの否定的な比較は決して見られません。たぶん、C#は実際には遅くないので。 –

+1

@Greg D:同意します。私はほぼ独占的に高性能で科学的指向の数値処理に取り組んでいます。 C#は非常に異なるパーツを持っています。プロファイリングは重要ですが、一般的にはC#をコードの適切なプロファイリングと調整を行うだけでC#と同じくらい速くすることができます。 –

+2

@Greg、Reed - マネージコードのパフォーマンスで見られる問題のほとんどは、このようなCPU時間ではなく、読み込み時間やメモリフットプリントなどです。これらのために、C++はまだ大きな利点を持っています(悪いプログラマは簡単にその利点を否定できますが)。 – Michael

0

私はCの最適化がC#と異なることは確信しています。また、少なくとも少しパフォーマンスが低下することを期待する必要があります。 .NETはフレームワークを使用してアプリケーションに別のレイヤーを追加します。

トレードオフは、より速い開発、巨大なライブラリ、および機能です。

2

のC#は、C#、安全でないコード内の演算部を実行しているとき、それはネイティブ実装だけでなく、実行しない

を境界チェックをしているのですか?

18

このコードの主な問題は、配列の境界を確認することになると思います。

C#で安全でないコードを使用してポインタの数学を使用すると、同じ(または潜在的に速い)コードを実現できるはずです。

この同じ問題はpreviously discussed in detail in this questionでした。

6

他の人が言っているように、側面の1つは境界チェックです。配列アクセスに関しては、コードに冗長性があります。変更がダウン〜8.8sまで〜5秒から合計時間をノックしたこと

int tmp1 = array1[i]; 
int tmp2 = array2[k]; 
if (tmp1 == tmp2) 
{ 
    calc = calc - array2[i] + array1[k]; 
} 
else 
{ 
    calc = calc + tmp1 - tmp2; 
} 

:私は、インナブロックを変更することで、多少パフォーマンスを向上させることができました。

+0

@ジョン:多分私は何かが欠けているかもしれませんが、私はあなたのバージョンとOPのバージョンとの間の重要なパフォーマンスの違いを測定することはできません。実際、パフォーマンスへの影響がそれほど大きくないとは思えません。 –

+0

どちらも特に私には当てはまりませんが、.NET 3.5と4.0b1の両方で確実にそうです。コンソールアプリケーションとして32ビットVistaで/ o +/debug-とコンパイルされました。私もi変数とk変数の範囲を変更しましたが、それは重要なことではありません。 –

+0

(私は十分な時間をテストして、ばかばかしではないことを確認しました。) –

1

アプリケーションのパフォーマンスクリティカルパスがすべてチェックされていない配列処理で構成されている場合は、C#で書き直すことをお勧めします。あなたのアプリケーションが既に言語Xで正常に動作している場合

しかし、その後、私はあなたが

何をリライトから達成したいん言語Yにそれを書き換えないようにお勧めしますか?少なくとも、ハイパフォーマンスのセクションには既にデバッグされたCコードを使用し、C#を使用して素敵なユーザーインターフェイスを入手するか、最新の豊富な.NETライブラリとの便利な統合を得るために、混合言語ソリューションを真剣に検討してください。

A longer answer on a possibly related theme.

4

楽しみのためだけに、私は、Visual Studio 2010でC#でこれを構築しようとした、とJITed解体で見ていた:

    else 
         calc = calc + array1[i] - array2[k]; 
000000cf mov   eax,dword ptr [ebp-10h] 
000000d2 add   eax,dword ptr [ebp-14h] 
000000d5 sub   eax,edx 
000000d7 mov   dword ptr [ebp-10h],eax 

彼らはジッタに多くの改善を行いましたCLRの4.0です。

関連する問題