4

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

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

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

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

4

13 に答える 13

16

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

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

于 2009-01-29T20:55:42.467 に答える
9

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

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

こうすることで、キャッシュを無駄にすることが少なくなり、速度が大幅に向上する可能性が高くなります。

于 2008-11-04T13:03:52.310 に答える
6

DSP ルーチンは C++ (マネージまたはアンマネージ) または C# のいずれかで、堅実な設計を使用して作成する必要があると思いますが、最初からすべてを最適化しようとするのではなく、コードをプロファイリングしてボトルネックを見つけ、それらを最適化する必要があります。あちらへ。

最初から「最適な」コードを生成しようとすると、そもそも機能するコードを書くことから気が散ってしまいます。多くの場合、コードの 10% だけが CPU 時間の 90% を担当しているため、最適化の 80% はコードの 20% にしか影響しないことに注意してください。(YMMV、アプリの種類による)

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

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

于 2008-11-04T11:56:55.173 に答える
4

これらのルーチンを C/C++ で書き直すことでパフォーマンス上の利点が得られるでしょうか?それとも、安全でないポインターに固執する必要がありますか?

理論的には、それは問題ではありません。完全なコンパイラーは、C であれ C++ であれ、コードを可能な限り最良のアセンブラーに最適化します。

ただし、実際には、特にポインター型アルゴリズムの場合、ほとんどの場合、C の方が高速です。アセンブリでコーディングせずにマシン コードに近づけることができます。

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

したがって、C++ に切り替えてもパフォーマンスが向上することはないでしょう。

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

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

-アダム

于 2009-01-29T19:58:35.217 に答える
3

最初に、「安全」と「安全でない」についての質問に答えさせてください。あなたは投稿で「アプリをできるだけ速くしたい」と言いましたが、それは「安全」または「管理」をいじりたくないという意味ですポインタ(ガベージコレクションについても言及しないでください)。

言語の選択に関して: C/C++ を使用すると、最近誰もが使用している派手なコンテナーに関連するオーバーヘッドなしで、基になるデータをはるかに簡単に操作できます。はい、セグフォルトを防ぐコンテナに寄り添うのは良いことですが、コンテナに関連するより高いレベルの抽象化はパフォーマンスを台無しにします.

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

本当にスマートになりたい場合は、すべての DSP コードを低レベル C で記述します。そして、それをより安全なコンテナー/マネージ ポインターと混ぜ合わせます。速度が上がると、補助輪を外す必要があります。速度が遅くなります。あなたはあまりにも落ち込んでいます。

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

編集: ps "seg faulting" は、すべての PC/x86 開発者にとって贅沢です。組み込みコードを書いているとき...セグフォルトは、プロセッサがwiideに入り、電源を入れ直すことによってのみ回復することを意味します;)。

于 2009-01-29T20:41:55.020 に答える
2

パフォーマンスを向上させる方法を知るには、ボトルネックを引き起こす可能性のあるコードの部分を知ることをお勧めします。

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

もう 1 つのボトルネックは、CPU とメモリの間のパスにあります。これは、アプリケーションでの大量のメモリ転送によるキャッシュ ミスです。最大のメリットは、キャッシュ ミスを最小限に抑えることにあります。キャッシュ ミスは、使用するプラットフォームとデータのレイアウト (ローカルか、メモリ全体に広がっているか) によって異なります。

しかし、あなたはすでに安全でないポインターを使用しているので、そのビットを自分で制御できるので、私の推測では、その点では、C (または C++) への移植のメリットはあまりありません。

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

于 2009-01-29T20:51:14.050 に答える
1

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

また、C#でのSSEの使用を確認することもできますか?

于 2009-02-04T03:28:25.540 に答える
1

あなたは本当にアプリをできるだけ速くしたいですか、それとも単に十分に速くしたいですか?それはあなたが次に何をすべきかを教えてくれます。

于 2009-02-03T00:58:59.320 に答える
1

あなたの質問は主に哲学的です。答えはこうです: プロファイリングするまで最適化しないでください。

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

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

于 2009-02-02T05:35:53.570 に答える
1

C# は SSE をサポートしていません (まだ、SSE 操作用の mono プロジェクトがあります)。そのため、SSE を使用した C/C++ の方が確実に高速です。

ただし、マネージドからネイティブへ、およびネイティブからマネージドへの移行は非常にコストがかかるため、注意が必要です。どちらかの世界にできるだけ長く留まります。

于 2009-02-02T20:26:36.813 に答える
1

アセンブラーなどで手動で最適化せずに、ハンドロールに固執する場合は、C# で問題ありません。残念ながら、これは実際には実験的にしか答えられない種類の質問です. あなたはすでにアンマネージ ポインター空間にいるので、C++ に直接移植しても速度に大きな違いは見られないというのが私の直感です。

ただし、最近同様の問題が発生し、 Intel Integrated Performance Primitivesライブラリを試した後、ハンドロールを破棄することになりました。そこで見たパフォーマンスの改善は非常に印象的でした。

于 2009-02-03T01:11:56.923 に答える
1

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

于 2009-02-02T04:49:41.760 に答える
0

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

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

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

于 2008-11-04T11:45:43.870 に答える