3

私はゲームエンジンを書いていますが、デバッグ用の現在のFPSを導出し、フレームレートを制限するための正確で正確な「デルタタイム」値を取得する方法が必要です(これは私たちのプロジェクトにとって重要です)。

少し調べてみると、これを行うための最良の方法の1つは、WinAPIのQueryPerformanceCounter関数を使用することです。フォワードカウンターの跳躍GetTicksCountを防ぐために使用する必要がありますが、それ自体はあまり正確ではありません。

ここでの問題QueryPerformanceCounterは、時間がワープバックした場合のように見える値を返す可能性があることです(つまり、呼び出しが過去の別の呼び出しよりも前の値を返す場合があります)。これは、特定のプロセッサコアで取得した値を別のプロセッサコアで取得した値と比較した場合にのみ発生します。これにより、この投稿を行う動機となった最終的な質問につながります。

  1. スレッドがすでに実行されている間にOSがスレッドを別のコアに「再割り当て」することはできますか、それともスレッドが特定のコアに割り当てられ、スレッドが終了するまでそれでしょうか。
  2. スレッドを再割り当てできない場合(少なくとも私にとっては非常に理にかなっています)、なぜ私が次のようなことを行うことができるのSetThreadAffinityMask(GetCurrentThread(),mask)ですか?Ogre3DはそのOgre::Timerクラス(Windows実装)でそれを行います、そして私はそれが時間を遡ることを避けるためであると仮定しています。しかし、それが真実であるためには、OSによってスレッドが1つのコアから別のコアに任意に移動される可能性を考慮する必要があります。これは、私にはかなり奇妙に思えます(理由はわかりません)。

今のところ知りたかったのはそれだけだったと思います。ありがとう。

4

6 に答える 6

2

スレッドにプロセッサアフィニティマスクがない限り、スケジューラは実行時間を与えるためにスレッドをプロセッサからプロセッサに移動します。プロセッサ間でスレッドを移動するとパフォーマンスが低下するため、スレッドを移動しないようにしますが、実行するプロセッサを与えることは、移動しないことよりも優先されます。したがって、通常、スレッドは移動します。

タイマーAPIも。 timeGetTimeはマルチメディアタイミング用に設計されているため、よりも少し正確ですGetTickCount

QueryPerformanceCounter().それでも、最も正確な測定値です。マイクロソフトはそれについてこれを言っています。

マルチプロセッサコンピュータでは、どのプロセッサが呼び出されるかは問題ではありません。ただし、基本入出力システム(BIOS)またはハードウェアアブストラクションレイヤー(HAL)のバグが原因で、プロセッサーごとに異なる結果が得られる可能性があります。スレッドのプロセッサ親和性を指定するには、SetThreadAffinityMask関数を使用します。

したがって、特定のコンピューターでタイミングテストを実行している場合は、QPCが逆行することを心配する必要はないかもしれません。いくつかのテストを実行して、それがマシンで重要かどうかを確認する必要があります。

于 2010-02-03T20:00:02.887 に答える
1

スレッドは、スレッドの実行中に再割り当てされる可能性があり、(アフィニティが設定されていない限り)再割り当てされます。Windowsは、パフォーマンスを最大化するためにすべてのプロセッサに負荷を分散します。

于 2010-02-03T19:48:44.883 に答える
1

SetAffinityMaskを使用してスレッドを1つのプロセッサにロックしたとしても、本当に運が悪く、ハードウェアがうまくいかない場合は、QPCが逆方向に実行される可能性があります。QPCが不正な値を返す場合に対処する方がよいでしょう。Windows 7では、この点でQPCが大幅に改善されていますが、ゲームを作成しているため、おそらくXPをターゲットにしているので役に立ちません。

また、スレッドアフィニティを設定しないでください。デッドロックが発生したり、奇妙なタイミングやパフォーマンスのバグが発生したり、一般的に悲しみを引き起こしたりする可能性があります。

于 2010-02-03T20:26:30.693 に答える
0

1)スレッドは、処理時間に余裕のあるコアにスレッドを割り当てることができます。これが、クアッドコアマシンでソフトウェアが50%を使用しているのをよく目にする理由ですが、グラフを確認すると、4つすべての半分を使用しています。

2)1を参照;)

于 2010-02-03T19:49:26.240 に答える
0

SetThreadAffinity()を使用することは、スレッドがタイミングのみを実行する場合を除いて、通常はお勧めできません。スレッドをシングルコアにロックすると、そもそもマルチコアシステムを使用するメリットがすべて失われます。アプリケーションは拡張できなくなります。アプリの複数のインスタンスを起動した場合でも、それらは単一のコアにロックされます。

于 2010-02-03T19:58:35.730 に答える
0

このため、タイミングを実行するときは通常、ゲームを単一のスレッドにロックする必要があります。パフォーマンスを測定するときにサブマイクロ秒の分解能が必要なため、私たちが見つけた効果的な方法はありません。

少し簡単にすることの1つは、エンジンが常に同時に実行される幅広いコンポーネントに分割されていることです(たとえば、ゲーム/ロジック「サーバー」、入力/グラフィックス「クライアント」、オーディオ、レンダリングはそれぞれ独自のスレッドです)。これらの各スレッドを独自のコアにロックし、それらの時間を個別に計測します。

同様に、たとえばレンダリングループは常にコア0で行われることがわかっているため、これをタイミングフレームレートに使用します。

于 2010-02-04T01:04:15.097 に答える