DSPルーチンをC / C ++で書き換える必要がありますか、それともC#の安全でないポインターで十分ですか?

StackOverflow https://stackoverflow.com/questions/261591

質問

現在、多くのデジタル信号処理を行うC#アプリケーションを作成しています。これには、多くの小さな微調整されたメモリxfer操作が含まれます。安全でないポインターを使用してこれらのルーチンを作成しましたが、最初に思ったよりもはるかに優れたパフォーマンスを発揮するようです。ただし、アプリをできるだけ速くしたいです。

これらのルーチンをCまたはC ++で書き換えることでパフォーマンス上の利点が得られますか、または安全でないポインターに固執する必要がありますか? C / C ++と比較して、パフォーマンスの観点から安全でないポインターがテーブルにもたらすものを知りたいです。

編集:私はこれらのルーチン内で特別なことは何もしていません。通常のDSPのことです。あるアレイから別のアレイへのキャッシュフレンドリーなデータ転送は、多くの乗算、加算、ビットシフトなどを伴います。 C / C ++ルーチンは、C#の対応するルーチンとほとんど同じに(同じではないにしても)見えるはずです。

編集:賢明な回答をありがとうございました。私が学んだことは、何らかのSSE最適化が行われない限り、直接ポートを実行するだけではパフォーマンスの大幅な向上は得られないということです。すべての最新のC / C ++コンパイラがそれを利用できると仮定して、試してみるのを楽しみにしています。誰かが結果に興味があるなら、私に知らせてください、そして、私はどこかにそれらを掲示します。 (ただし時間がかかる場合があります)。

役に立ちましたか?

解決

実際には、画像処理領域でのみ、あなたが求めていることをほぼ正確に実行しました。私はC#の安全でないポインターから始め、次にC ++ / CLIに移動し、今ではすべてをC ++でコーディングしています。そして実際、そこからC ++のポインターからSSEプロセッサー命令に変更したので、私はずっと行きました。まだアセンブラーに到達していませんが、必要かどうかはわかりませんが、SSEがインラインアセンブラーと同じくらい高速であることができることを示すCodeProjectの記事を見ました。

私が行ったときに起こったのは、アルゴリズムが安全でないポインターを使用したC#の1秒あたり約1.5〜2フレームから、現在は1秒あたり40フレームになったことです。 C#とC ++ / CLIは、ポインターを使用してもC ++よりも明らかに遅く、これらの言語では1秒あたり10フレームを超えることができませんでした。 C ++に切り替えるとすぐに、毎秒15〜20フレームのようなものがすぐに得られました。さらにいくつかの巧妙な変更とSSEにより、最大40フレーム/秒になりました。そうです、私の経験を早くしたいのなら、下げる価値はあります。明らかなパフォーマンスの向上があります。

他のヒント

DSPコードを最適化するもう1つの方法は、キャッシュフレンドリーにすることです。信号に適用するフィルターが多数ある場合は、すべてのフィルターを各ポイントに適用する必要があります。つまり、最も内側のループはデータではなくフィルター上にある必要があります。例:

for each n do t´[n] = h(g(f(t[n])))

これにより、キャッシュのトラッシュが大幅に少なくなり、速度が大幅に向上する可能性が高くなります。

C ++(マネージドまたはアンマネージド)またはC#でDSPルーチンを作成し、最初からすべてを最適化せずに堅牢な設計を使用してから、コードをプロファイリングしてボトルネックを見つけて試してくださいそれらを最適化する。

「最適」を作成しよう最初からのコードは、そもそも動作するコードを書くことからあなたをそらすでしょう。多くの場合、CPU時間の90%を占めるのはコードの10%だけであるため、最適化の80%がコードの20%にのみ影響することに注意してください。 (YMMV、アプリケーションのタイプに依存するため)

グラフィックツールキットでアルファブレンディングの使用を最適化しようとしていたとき、SIMDの「ベアメタル」を使用しようとしていました。最初の方法:インラインアセンブラ。コンパイラーは、個々のオペコードを再配置し、CPU内のさまざまな処理ユニットの使用を最大化することで、コンパイラーが読み取り可能なC ++を組み込み関数でさらに最適化できるため、純粋なアセンブリーよりもSIMD組み込み関数を使用する方がよいことがわかりました。

コンパイラの能力を過小評価しないでください!

  

パフォーマンス上のメリットはありますか   C / C ++でこれらのルーチンを書き換えることから   または安全でないポインターに固執する必要がありますか?

理論上は問題ではありません-完璧なコンパイラーは、CまたはC ++のコードを最適なアセンブラーに最適化します。

ただし、実際には、特にポインター型アルゴリズムの場合、Cはほぼ常に高速です。アセンブリでコーディングせずにマシンコードに到達できる限り近いです。

C ++は、パフォーマンスの面では何ももたらしません。Cのオブジェクト指向バージョンとして構築されており、プログラマにとってより多くの機能と使いやすさを備えています。特定のアプリケーションはオブジェクト指向の観点から恩恵を受けるため、パフォーマンスが向上することもありますが、パフォーマンスを向上させることを意図したものではありません。別のレベルの抽象化を提供して、複雑なアプリケーションのプログラミングを容易にします。 p>

つまり、いいえ、C ++に切り替えてもパフォーマンスは向上しません。

ただし、時間を費やすことを避けるよりも、見つけることの方が重要であると思われます。移植して分析することは価値のある活動だと思います。プロセッサにC ++またはJavaを使用するための特定の命令があり、コンパイラがそれらを知っている場合、Cで利用できない機能を利用できる可能性があります。可能性は低いですが、可能です。

ただし、DSPプロセッサは悪名高い複雑な獣であり、アセンブリに近づけば近づくほどパフォーマンスが向上します(つまり、コードを手で調整するほど)。 CはC ++よりもアセンブリにはるかに近い。

-アダム

まず、「安全」に関する質問に答えさせてください。 vs「安全でない」:投稿で「アプリをできるだけ速くしたい」と言いました。つまり、「安全」を台無しにしたくないということです。または「管理」ポインター(ガベージコレクションについても言及しないでください)。

言語の選択について: C / C ++を使用すると、最近誰もが使用している派手なコンテナに関連するオーバーヘッドなしで、基になるデータをはるかに簡単に操作できます。はい、セグメンテーション違反を防止するコンテナによって寄り添われるのは nice です。しかし、コンテナに関連付けられた抽象化のより高いレベルは、パフォーマンスを破滅します。

私の仕事では、コードを高速で実行する必要があります。例は、ポインターとマスキング操作および固定小数点DSPフィルターを使用して動作するポリフェーズリサンプラーです...これらの巧妙なトリックは、メモリの低レベル制御とビット操作==>なしでは実際に不可能です。 C / C ++に固執すると言います。

本当にスマートになりたい場合は、すべてのDSPコードを低レベルCで記述してください。そして、より安全なコンテナー/マネージポインターと混ぜて...スピードが上がったら、トレーニングホイールを外す必要があります。 。彼らはあなたを遅くしすぎます。

(参考までに、トレーニングホイールの取り外しについて:ポインターの使用が適切かどうかを確認するために、C DSPコードをさらにオフラインでテストする必要があります... o / wそれはセグフォールトになります。)

編集:p.s. 「セグ障害」すべてのPC / x86開発者向けの贅沢品です。埋め込みコードを記述しているとき... segフォールトは、プロセッサがwuidesに入り、パワーサイクリングによってのみ回復されることを意味します;)。

パフォーマンスを向上させる方法を知るには、ボトルネックを引き起こす可能性のあるコードの部分を知っておくとよいでしょう。

小さなメモリ転送について説明しているので、すべてのデータがCPUのキャッシュに収まると思います。その場合、達成できる唯一の利点は、CPUの組み込み関数の動作方法を知ることです。通常、CPUの組み込み関数に最も精通しているコンパイラはCコンパイラです。したがって、ここでは、移植によってパフォーマンスを改善できると思います。

もう1つのボトルネックは、CPUとメモリの間のパスにあります-アプリケーションでの大量のメモリ転送によるキャッシュミス。最大の利点は、使用するプラットフォームとデータのレイアウト(ローカルまたはメモリ全体に分散するかどうか)に依存するキャッシュミスの最小化にあります。

しかし、既に安全でないポインターを使用しているので、そのビットは自分の制御下にあるので、私の推測では:その側面では、C(またはC ++)への移植から多くの利益を得ることはありません。

結論:アプリケーションの小さな部分をCに移植したい場合があります。

すでに安全でないコードで記述しているのを見て、それをC dllに変換してC#内から呼び出すのは比較的簡単だと思います。プログラムの最も遅い部分を特定してからCに置き換えてからこれを行います。

あなたの質問の大部分は哲学的です。答えは次のとおりです。プロファイルするまで最適化しないでください。

改善するかどうかを尋ねます。さて、あなたはNパーセントの改善を得るでしょう。それで十分な場合(組み込みシステムで20ミリ秒で200回実行するコードが必要な場合など)、問題ありません。しかし、それで十分でない場合はどうなりますか?

最初に測定してから、コードの一部を同じ言語でより高速に書き換えられるかどうかを確認する必要があります。おそらく、不必要な計算を避けるためにデータ構造を再設計できます。おそらく、メモリの再割り当てをスキップできます。線形の複雑さでできるのに、二次の複雑さで何かをするのかもしれません。測定するまで表示されません。これは通常、すべてを別の言語で書き換えるよりも時間の無駄がはるかに少なくなります。

C#はSSEをサポートしていません(ただし、SSE操作用のモノラルプロジェクトがあります)。そのため、SSEを使用したC / C ++は間違いなく高速になります。

ただし、管理からネイティブへ、およびネイティブから管理への移行は非常に高価なので、注意する必要があります。どちらかの世界にできるだけ長く滞在します。

アプリを可能な限り高速にしたいですか、それとも単に十分に高速にしたいですか?これで、次に何をすべきかがわかります。

アセンブラーなどで手を最適化せずに、ハンドロールに固執する場合は、C#で問題ありません。残念ながら、これは実験的にしか答えられないような質問です。既にアンマネージポインタースペースにいるので、私の直感では、C ++への直接ポートでは速度に大きな違いは見られません。

ただし、最近同様の問題が発生し、 Intel Integrated Performance Primitives ライブラリ。そこで見たパフォーマンスの改善は非常に印象的でした。

Mono 2.2は、これで SIMD をサポートするようになりました。マネージドコードと生の速度の両方の世界。

c#でSSEを使用することは可能ですか?

DSPコードに最適化する必要がある必要のアルゴリズムがある場合は、CまたはC ++ではなくアセンブリで実際に記述することをお勧めします。

一般的に、最新のプロセッサとハードウェアでは、最適化に伴う労力を必要とする、または保証するシナリオはそれほど多くありません。実際にパフォーマンスの問題を特定しましたか?そうでない場合は、おそらくあなたが持っているものに固執するのが最善です。安全でないC#は、ほとんどの単純な算術演算の場合、C / C ++よりも大幅に遅くなることはほとんどありません。

C ++ / CLIを検討しましたか?その場合、両方の長所を活用できます。必要に応じてインラインアセンブラを使用することもできます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top