9

.NET アプリケーションを 64 ビット JIT と 32 ビット JIT で実行することから切り替えたときに、パフォーマンス、メモリなどの点で、通常とは異なる予期しない結果が発生しましたか? 私は良いことに興味がありますが、人々が遭遇した驚くほど悪い問題にもっと興味があります.

32 ビットと 64 ビットの両方で展開される新しい .NET アプリケーションを作成中です。アプリケーションの移植に関する問題に関連する多くの質問がありました - 私はプログラミング/移植の観点からの「問題」には関心がありません。(つまり: ネイティブ/COM 相互運用を正しく処理する、構造体のサイズを変更する構造体に埋め込まれた参照型など)

しかし、この質問とその答えは私に考えさせました - 私が見落としている他の問題は何ですか?

この問題を回避したり、その 1 つの側面に触れたりする多くの質問やブログ投稿がありましたが、適切な問題のリストをまとめたものは見たことがありません。

特に、私のアプリケーションは非常に CPU バウンドであり、大量のメモリ使用パターン (したがって、そもそも 64 ビットが必要) であり、本質的にグラフィカルです。私は、64 ビット Windows (.NET 3.5sp1 を使用) で実行されている CLR または JIT に、他にどのような隠れた問題が存在する可能性があるかを懸念しています。

現在わかっているいくつかの問題を次に示します。

64 ビット Windows の JIT で発見された他の具体的な問題と、パフォーマンスの回避策があるかどうかを知りたいです。

皆さん、ありがとうございました!

- - 編集 - - -

明確にするために-

早期に最適化しようとするのはよくないことだと認識しています。システムを二番目に推測することはしばしば悪いことであることを私は知っています。また、64 ビットへの移植性には独自の問題があることも知っています。これを支援するために、64 ビット システムで毎日実行およびテストしています。等

ただし、私のアプリケーションは一般的なビジネス アプリケーションではありません。これは、科学的なソフトウェア アプリケーションです。一度に何時間も、すべてのコア (高度にスレッド化されている) で 100% の CPU を使用して座っている多くのプロセスがあります。

私はアプリケーションのプロファイリングに多くの時間を費やしており、それが大きな違いを生み出しています。ただし、ほとんどのプロファイラーは JIT の多くの機能を無効にしているため、プロファイラーで実行している場合、メモリ割り当て、JIT のインライン化などの細部を突き止めるのは非常に困難です。したがって、質問が必要です。

4

8 に答える 8

4

.NET で特に厄介なパフォーマンスの問題は、不十分な JIT に関連しています。

https://connect.microsoft.com/VisualStudio/feedback/details/93858/struct-methods-should-be-inlined?wa=wsignin1.0

基本的に、インライン化と構造体は x64 ではうまく連携しません (ただし、このページではインライン化が機能するようになったが、その後の冗長コピーが排除されていないことを示唆していますが、わずかなパフォーマンスの違いを考えると疑わしいように思えます)。

いずれにせよ、これに十分な時間 .NET と格闘した後の私の解決策は、数値集約型のものには C++ を使用することです。構造体を扱っておらず、境界チェックが最適化されていない配列を使用している .NET の「良い」ケースでも、C++ は .NETに勝っています。

内積よりも複雑なことをしている場合、状況は急速に悪化します。.NETコードは長くて読みにくく(手動でインライン化する必要があるか、ジェネリックを使用できないため)、はるかに遅くなります。

私はC++ でEigenを使用するように切り替えました。これは非常に優れており、読みやすいコードと高いパフォーマンスが得られます。次に、薄い C++/CLI ラッパーが、計算エンジンと .NET ワールドの間の接着剤を提供します。

Eigen はテンプレートのメタプログラミングによって機能します。in は、ベクトル式を SSE 組み込み命令にコンパイルし、最も厄介なキャッシュ関連のループのアンロールと再配置を行います。線形代数に焦点を当てていますが、整数および非行列配列式でも機能します。

したがって、たとえば、Pが行列の場合、この種のものはうまくいきます:

1.0 /  (P.transpose() * P).diagonal().sum();

...一時的に転置された P のバリアントを割り当てず、行列の積全体を計算するのではなく、必要なフィールドのみを計算します。

そのため、完全な信頼で実行できる場合 (C++/CLI 経由で C++ を使用するだけ)、はるかにうまく機能します。

于 2010-02-25T14:34:57.267 に答える
3

私がよく行く IRC チャンネルから問題を聞いたのを覚えています。このインスタンスの一時コピーを最適化します。

EventHandler temp = SomeEvent;
if(temp != null)
{
    temp(this, EventArgs.Empty);
}

競合状態を元に戻し、null 参照例外を引き起こす可能性があります。

于 2009-03-11T15:49:08.603 に答える
1

あなたは移植の問題について言及しましたが、それらは懸念すべき問題です。私は(明らかに)あなたのアプリケーションを知りませんが、JIT を推測しようとするのは、多くの場合完全に時間の無駄です。JIT を作成する人は、x86/x64 チップ アーキテクチャを深く理解しており、おそらく地球上の他の誰よりもパフォーマンスが高く、パフォーマンスが悪いものを知っています。

はい、これとは異なる独自のコーナー ケースが存在する可能性はありますが、「新しいアプリケーションを作成中」の場合は、JIT コンパイラについて心配する必要はありません。どこかで回避できるばかげたループがあり、JIT を再推測することで得られるパフォーマンスの 100 倍の改善が得られる可能性があります。ORM の作成中に遭遇した問題を思い出します。コードを見て、そこからいくつかのマシン命令を微調整できると考えていました...もちろん、コードはオフになり、ネットワーク経由でデータベース サーバーに接続されました。 、そのため、別の場所でミリ秒単位で制限されていたプロセスからマイクロ秒単位でトリミングしていました。

パフォーマンス調整の普遍的なルール... パフォーマンスを測定していない場合、ボトルネックがどこにあるのかわかりません。わかっていると思い込んでいるだけで、おそらく間違っているでしょう。

于 2009-03-11T15:38:34.900 に答える
1

ほとんどの場合、Visual Studio とコンパイラは問題をうまく隠してくれます。ただし、プラットフォーム (x86 と x64) を自動検出するようにアプリを設定し、32 ビットのサードパーティ dll に依存している場合に発生する可能性のある大きな問題が 1 つあります。この場合、64 ビット プラットフォームでは、64 ビットの規約と構造を使用して dll を呼び出そうとしますが、うまくいきません。

于 2009-03-11T15:32:49.080 に答える
0

64 JITは、このような64ビットアーキテクチャCPUを利用するように完全に開発/移植されていないため、問題が発生していると思います。アセンブリの「エミュレート」動作が発生し、問題や予期しない動作が発生する可能性があります。これを回避できる場合や、タイムクリティカルな計算やアルゴリズムを記述できる高速な64c++コンパイラがあるかどうかを調べます。しかし、情報を見つけるのが難しい場合や、分解されたコードを読む時間がない場合でも、マネージコードの外部で大量の計算を行うことで、発生する可能性のある問題が減り、パフォーマンスが向上することは間違いありません[すでにこれを行っていることは確かです。ただ言及するだけです:)]

于 2010-02-06T07:57:48.833 に答える
0

A profiler shouldn't significantly influence your timing results. If the profiler overheads really are "significant" then you probably can't squeeze much more speed out of your code, and should be thinking about looking at your hardware bottlenecks (disk, RAM, or CPU?) and upgrading. (Sounds like you are CPU bound, so that's where to start)

In general, .net and JIT frees you from most of the porting problems of 64 bit. As you know, there are effects relating to the register size (memory usage changes, marshalling to native code, needing all parts of the program to be native 64-bit builds) and some performance differences (larger memory map, more registers, wider buses etc), so I can't tell you anything more than you already know on that front. The other issues I've seen are OS rather than C# ones - there are now different registry hives for 64-bit and WOW64 applications, for example, so some registry accesses have to be written carefully.

It's generally a bad idea to worry about what the JIT will do with your code and try to adjust it to work better, because the JIT is likely to change with .net 4 or 5 or 6 and your "optimisations" may turn into inefficiencies, or worse, bugs. Also bear in mind that the JIT compiles the code specifically for the CPU it is running on, so potentially an improvement on your development PC may not be an improvement on a different PC. What you get away with using today's JIT on today's CPU might bite you in a years time when you upgrade something.

Specifically, you cite "properties are not inlined on x64". By the time you have run through your entire codebase turning all your properties into fields, there may well be a new JIT for 64 bit that does inline properties. Indeed, it may well perform better than your "workaround" code. Let Microsoft optimise that for you.

You rightly point out that your memory profile can change. So you might need more RAM, faster disks for virtual memory, and bigger CPU caches. All hardware issues. You may be able to reduce the effect by using (e.g.) Int32 rather than int but that may not make much difference and could potentially harm performance (as your CPU may handle native 64-bit values more efficiently than half-size 32-bit values).

You say "startup times can be longer", but that seems rather irrelevant in an application that you say runs for hours at 100% CPU.

So what are you really worried about? Maybe time your code on a 32-bit PC and then time it doing the same task on a 64-bit PC. Is there half an hour of difference over a 4 hour run? Or is the difference only 3 seconds? Or is the 64 bit PC actually quicker? Maybe you're looking for solutions to problems that don't exist.

So back to the usual, more generic, advice. Profile and time to identify bottlenecks. Look at the algorithms and mathematical processes you are applying, and try to improve/replace them with more efficient ones. Check that your multithreading approach is helping rather than harming your performance (i.e. that waits and locks are avoided). Try to reduce memory allocation/deallocation - e.g. re-use objects rather than replacing them with new ones. Try to reduce the use of frequent function calls and virtual functions. Switch to C++ and get rid of the inherent overheads of garbage collection, bounds checking, etc. that .net imposes. Hmmm. None of that has anything to do with 64 bit, does it?

于 2010-02-06T08:34:22.757 に答える
-1

私は 64 ビットの問題にはあまり詳しくありませんが、1 つコメントがあります。

約 97% の確率で、わずかな効率性を忘れる必要があります。時期尚早の最適化は諸悪の根源です。-- ドナルド・クヌース

于 2009-03-11T15:26:44.803 に答える