9

DirectX 11 C++ アプリケーションの問題を 1 週間以上調査してきたので、この問題を追跡するのに役立つ洞察を得るために、StackOverflow の善良な人々に頼っています。

私のアプリケーションは、ほとんどの場合、1 秒あたり 60 ~ 90 フレームで実行されますが、数秒ごとに、完了するまでに約 3 分の 1 秒かかるフレームが取得されます。多くの調査、デバッグ、およびさまざまなコード プロファイラーの使用の後、DirectX API の呼び出しに絞り込みました。ただし、遅いフレームから次のフレームまで、速度低下の原因となる API 呼び出しが常に同じであるとは限りません。私の最新の実行では、ストールする呼び出し (常に約 5 分の 1 秒) は次のとおりです。

  • ID3D11DeviceContext:UpdateSubresource
  • ID3D11DeviceContext:DrawIndexed
  • IDXGISwapChain:現在

ストールするのは同じ関数ではないだけでなく、これらの関数 (主に最初の 2 つ) のそれぞれが、私のコード内のさまざまな場所から次から次へと遅い呼び出しをしている可能性があります。

複数のプロファイリング ツールと、物事を測定するためにコードに配置した独自の高解像度タイマーによると、この「しゃっくり」は 3 秒弱 (~2.95) の一貫した間隔で発生することがわかりました。

このアプリケーションは、外部ハードウェアからデータを収集し、DirectX を使用してそのデータをリアルタイムで視覚化します。アプリケーションの実行中、ハードウェアはアイドル状態またはさまざまな速度で実行されている可能性があります。ハードウェアが高速になるほど、より多くのデータが収集され、視覚化する必要があります。このバグの特徴のいくつかを検討する際に役立つ可能性があるため、これを指摘します。

  • ハードウェアがアイドル状態の場合、長いフレームは発生しません。ソフトウェアは既に持っているデータを再描画するだけでよく、新しいデータを GPU に転送する必要がないため、これは私には理にかなっています。
  • ただし、長いフレームは、ハードウェアの実行速度に関係なく、これらの一貫した 3 秒間隔で発生します。したがって、アプリケーションが毎秒 2 倍の量のデータを収集している場合でも、長いフレームの頻度は変わりません。
  • これらの長いフレームの長さは非常に一貫しています。常に 0.25 から 0.3 秒の間です (一貫しているのは DirectX API の呼び出しが遅いため、全体的なフレーム期間の変動はその呼び出しの外部にあると思います)。
  • 先週のフィールド テスト中 (私が最初に問題を発見したとき)、アプリケーションを数回実行した後、長い時間 (おそらく 20 分以上) 継続的にテストを行った後、プログラムを監視する以外にプログラムとあまり対話せずに、しゃっくりは消えます。アプリケーションの一部の機能を操作したり、プログラムを再起動したりすると、しゃっくりが戻ってきます。私には意味がありませんが、GPU が問題を「把握」して修正したように見えますが、以前に行っていた作業のパターンを変更すると元に戻りました。残念ながら、ハードウェアの性質上、ラボ環境でこれを再現することは困難です。

このバグは、非常によく似たハードウェア (デュアル GTX580 カード) を持つ 2 つの異なるマシンで一貫して発生しています。ただし、アプリケーションの最近のバージョンでは、この問題は発生しませんでした。残念ながら、それ以降、コードには多くの変更が加えられているため、問題の原因となっている特定の変更を特定することは困難です。

グラフィックドライバーを考えて最新版にアップデートしましたが、変わりませんでした。また、両方のコンピューターに他の変更が加えられた可能性、または両方で実行されているソフトウェアの更新が GPU に問題を引き起こしている可能性も考えました。しかし、アプリケーションの実行中に両方のマシンで実行されている Microsoft Security Essentials 以外は考えられません。すでにリアルタイム保護機能を無効にしようとしましたが、役に立ちませんでした。

オフにできる外部プログラムが原因であることを望んでいますが、最終的には、GPU が数秒ごとに調整を行わなければならない原因となっている DirectX API で何か間違った/不適切なことをしているに違いないのではないかと心配しています。GPU でデータを更新する方法が間違っている可能性があります (表示するデータを収集しているときにのみ遅延が発生するため)。その後、GPU は数秒ごとに停止し、停止中にたまたま呼び出された API 関数は、通常よりも速く戻ることができませんか?

どんな提案でも大歓迎です!

ありがとう、ティム

更新 (2013.01.21):

私は最終的にあきらめて、このバグが発生していないポイントを見つけるまで、アプリケーションの以前のリビジョンをさかのぼって検索しました。次に、バグが発生し始めた正確な時期を見つけ、問題の原因を特定できるまで、リビジョンごとにリビジョンを進めました。この問題は、「符号なし整数」フィールドを頂点タイプに追加した後に発生し始めました。このフィールドには、大きな頂点バッファーが割り当てられています。頂点バッファーのサイズが原因で、この変更によりサイズが 184.65 MB (1107.87 MB から 1292.52 MB) 増加しました。実際には、頂点構造にこの余分なフィールドが必要なので、全体の頂点バッファー サイズを削減する他の方法を見つけ、704.26 MB に減らしました。

私の最善の推測は、そのフィールドとそれに必要な余分なメモリの追加により、GPU のしきい値/制限を超えたということです。それが総メモリ割り当ての超過だったのか、それとも単一の頂点バッファへの制限の超過だったのかはわかりません。いずれにせよ、この超過により、GPU は数秒ごとに余分な作業 (おそらく CPU との通信) を行う必要があったため、API への呼び出しはこれを待つ必要がありました。大きな頂点バッファーの影響を明確にする情報を誰かが持っている場合は、ぜひ聞いてください!

時間と提案をくれたみんなに感謝します。

4

1 に答える 1

1

1) VSYNCを回してみる

2) 大量のメモリの割り当て/割り当て解除を行っていますか? プログラムの最初にメモリを割り当てようとし、割り当てを解除せず、単純に上書きします (これはおそらく updatesubresource で行っていることです)。

3) ハードウェア デバイスとのやり取りを別のスレッドに配置します。デバイスがアプリケーションへのデータの受け渡しを完全に完了したら、それを GPU に読み込みます。デバイスがメイン スレッドを制御しないようにします。デバイスがメインスレッドを頻繁にブロックしていると思われ、完全に推測していますが、デバイスから GPU にデータを直接コピーしている場合、デバイスが時々ブロックされ、それが原因で速度が低下します。

于 2013-01-18T20:38:31.260 に答える